﻿/// <reference path="../jqGrid/jqGrid-4.6.0/i18n/grid.locale-en.js" />
/// <reference path="../jqGrid/jqGrid-4.6.0/jquery.jqGrid.src.js" />
/// <reference path="../jQuery/jquery-1.11.0.js" />
/// <reference path="../jQuery-UI/jquery-ui-1.10.4.custom.js" />
/// <reference path="i18n/vpGrid.locale-en.js" />

///Author : Henri d'Orgeval

(function (window, undefined) {
    window.vpGrid = window.vpGrid || {};
    var vpGrid = window.vpGrid;
    vpGrid.version = "0.9.2";
})(this);


(function (window, undefined) {
    window.jsTrace = window.jsTrace || {};
    var jsTrace = window.jsTrace;
    jsTrace.version = "0.7.0";

    jsTrace.options = {
        remoteLogging: false,
        remoteUrl: "http://trace.aspx",
        consoleLogging: true
    };

    function isNullOrUndefined(input) {
        try {
            if (input === undefined) {
                return true;
            }

            if (input === null) {
                return true;
            }

            return false;

        } catch (e) {
            logExceptionToConsole(e);
            return false;
        }
    }
    function isEmpty(input) {
        try {
            if (input === undefined) {
                return true;
            }

            if (input === null) {
                return true;
            }

            //check for native types
            if (typeof input === "number") {
                return false;
            }

            if (typeof input === "function") {
                return false;
            }

            if (input.length && input.length === 0) {
                return true;
            }

            // check for empty literal object
            for (var i in input) {
                if (input.hasOwnProperty && input.hasOwnProperty(i)) {
                    return false;
                }
            }

            return true;

        } catch (e) {
            logExceptionToConsole(e);
            return false;
        }
    }
    function isNullOrUndefinedOrEmpty(input) {
        try {
            if (isNullOrUndefined(input)) {
                return true;
            }

            if (isEmpty(input)) {
                return true;
            }

            return false;

        } catch (e) {
            logExceptionToConsole(e);
            return false;
        }
    }
    function toSmallDateTime(input) {
        /// <signature>
        /// <summary>Transform input date in the following format : 'yyyy/mm/dd hh:mm:ss'</summary>
        /// <param name="input" type="Date">Input Date</param>
        /// <returns type="String">Returns the formated date. If something goes wrong, error message is returned.</returns>
        /// </signature>
        try {
            if (input === undefined || input === null) {
                input = new Date();
            }

            if (input.getDate === undefined) {
                input = new Date();
            }

            var dd = input.getDate();
            var mm = input.getMonth() + 1;
            var yyyy = input.getFullYear();
            var hh = input.getHours();
            var mn = input.getMinutes();
            var ss = input.getSeconds();

            if (dd < 10) {
                dd = '0' + dd;
            }
            if (mm < 10) {
                mm = '0' + mm;
            }

            if (hh < 10) {
                hh = '0' + hh;
            }

            if (mn < 10) {
                mn = '0' + mn;
            }

            if (ss < 10) {
                ss = '0' + ss;
            }

            var now = yyyy + '/' + mm + '/' + dd + ' ' + hh + ':' + mn + ':' + ss;
            return now;

        } catch (e) {
            return e.message;
        }
    }
    function logExceptionToConsole(ex) {
        try {
            if (ex === undefined) {
                return;
            }

            if (console === undefined) {
                return;
            }

            if (console.error === undefined) {
                return;
            }

            var smalldateTime = toSmallDateTime(new Date());
            var msg = "[" + smalldateTime + "] ";

            if (ex.stack) {
                msg += ex.stack;
                console.error(msg);
                return;
            }

            if (ex.message) {
                msg += ex.message;
            }

            console.error(msg);

        } catch (e) {
            var msg = e.message;
            try {
                console.error("Unexpected error in method logExceptionToConsole : " + msg);
            } catch (e2) {

            }
        }
    }
    function logErrorToConsole(err) {
        try {
            if (err === undefined) {
                return;
            }

            if (console === undefined) {
                return;
            }

            if (console.error === undefined) {
                return;
            }

            var smalldateTime = toSmallDateTime(new Date());
            var msg = "[" + smalldateTime + "] ";

            if (err.functionName) {
                msg += "[function: " + err.functionName + "] ";
            }

            if (err.callerName) {
                msg += "[caller name: " + err.callerName + "] ";
            }

            if (err.message) {
                msg += err.message;
            }

            if (err.info) {
                msg += '\n' + err.info;
            }

            //if (err.callerCode) {
            //    msg += "\n[caller code: " + err.callerCode + "] ";
            //}

            console.error(msg);

        } catch (e) {
            logExceptionToConsole(e);
        }
    }
    function logError(err) {
        /// <signature>
        /// <summary>Log application error on all configured output devices (Console, Remote Server, custom DOM element</summary>
        /// <param name="err" type="Object">literal object that is like { message : "xxx", functionName : "yyy", info : "ttt" }</param>
        /// </signature>
        try {
            // try find caller
            try {
                var caller = logError.caller;
                var callerName = caller.name.toString();
                var callerCode = caller.toString();
                err.callerName = callerName;
                err.callerCode = callerCode;

            } catch (e1) {

            }

            logErrorToConsole(err);

            //TODO : remote logging

            //TODO : log inside specific DOM element

        } catch (e) {
            logExceptionToConsole(e);
        }
    }
    function sendExceptionToRemote(ex, options) {
        try {
            if (isNullOrUndefinedOrEmpty(options)) {
                logError({
                    message: "jsTrace options object is invalid. Errors cannot be sent to remote server."
                });
                return;
            }

            //check if sending messages to remote server is enabled
            if (options.remoteLogging === false) {
                return;
            }

            //get url to be requested
            var url = options.remoteUrl;

            if (isNullOrUndefinedOrEmpty(url)) {
                logError({
                    message: "Remote Url is not defined in the options object. Errors cannot be sent to remote server.",
                    info : "Check that options object passed to jsTrace contains a property called remoteUrl with a valid url value."
                });
                return;
            }

            if (typeof encodeURIComponent !== "function") {
                logError({
                    message: "encodeURIComponent is not a function. Errors cannot be sent to remote server.",
                    info : "check if encodeURIComponent function exists in the current scope."
                });
                return;
            }

            if (isNullOrUndefinedOrEmpty(JSON)) {
                logError({
                    message: "JSON object does not exist or is not valid. Errors cannot be sent to remote server.",
                    info: "check if JSON object exists in the current scope."
                });
                return;
            }

            if (typeof JSON.stringify !== "function") {
                logError({
                    message: "stringify method on JSON object does not exist or is not valid. Errors cannot be sent to remote server.",
                    info: "check if JSON object has a stringify method."
                });
                return;
            }

            var requestUrl = url + '&error=' + encodeURIComponent(JSON.stringify(ex));
            var img = new Image();
            img.src = requestUrl;

        } catch (e) {
            logExceptionToConsole(e);
        }
    }

    


})(this);

(function (window, $, undefined) {
    try {
        window.vpGrid = window.vpGrid || {};
        var vpGrid = window.vpGrid;

        //private options
        // to override these options : call the vpGrid.init method with an option parameter
        var vpGridOptions = {
            enableRemoteLogging: false,
            enableFilterToolbar: true,
            enableOperatorsInFilterToolbar: false,
            enableMultiSelect: false,
            enableRowCheckbox: true,
            defaultCaption: "Default caption",
            enableCustomCaption: false,
            enableCustomStatusBar: false,
            enableSummaryRows: false,
            placeSummaryRowsOnTop: false,
            numberOfSummaryRows : 1,
            numberOfVisibleRows: 11,
            loadGridOnPageLoad: true,
            minColWidth: 60,
            fitToBrowserWidth: true,
            fixedColWidth: false,
            autoInsertNewLineAtBottom : false, // not implemented yet
            datepickerOptions: {
                showOtherMonths: true,
                selectOtherMonths: true
            }
        };

        var vpGridAjaxOptions = {
            error: logAjaxError,
            statusCode: {
                400: function () {
                    logAjaxHttpStatusCode(400);
                },
                401: function () {
                    logAjaxHttpStatusCode(401);
                },
                403: function () {
                    logAjaxHttpStatusCode(403);
                },
                500: function () {
                    logAjaxHttpStatusCode(500);
                },
                503: function () {
                    logAjaxHttpStatusCode(503);
                },
                0: function () {
                    logAjaxHttpStatusCode(0);
                }
            }
        };

        // variable to create unique client side id for new inserted rows
        vpGrid.guid = vpGrid.guid || 1;

        // Public Data attributes used by vpGrid
        // data tags attributes are used to inject any kind of behavior within the Grid
        vpGrid.HtmlDataTag = vpGrid.HtmlDataTag || {};
        vpGrid.HtmlDataTag.TimelineSequence = "data-vp-grid-timeline-sequence";
        vpGrid.HtmlDataTag.DataSource = "data-vp-grid-datasource";
        vpGrid.HtmlDataTag.DataSourceType = "data-vp-grid-datasource-type";
        vpGrid.HtmlDataTag.Url = "data-vp-grid-url";
        vpGrid.HtmlDataTag.UIElement = "data-vp-grid-ui-element";
        vpGrid.HtmlDataTag.Handlers = "data-vp-grid-handlers";
        vpGrid.HtmlDataTag.HandlersRegistered = "data-vp-grid-handlers-registered";
        vpGrid.HtmlDataTag.UIDisabled = "data-vp-grid-ui-disabled";
        vpGrid.HtmlDataTag.UIDisabledOn = "data-vp-grid-ui-disabled-on";
        vpGrid.HtmlDataTag.UIIdentifier = "data-vp-grid-ui-id";
        vpGrid.HtmlDataTag.SummaryIdentifier = "data-vp-grid-summary-id";
        vpGrid.HtmlDataTag.ImportColumnValue = "data-vp-grid-import-column-value";

        // This Data tag is used to know if the current element has been attached to its container. For exemple the element is defined outside its container and then placed at a specific time at a specific place in the DOM.
        vpGrid.HtmlDataTag.UIInPlace = "data-vp-grid-ui-inplace";

        vpGrid.HtmlDataTag.UIContentPlaceholder = "data-vp-grid-ui-content-placeholder";


        //default values for data tag
        vpGrid.HtmlDataTag.DefaultValue = vpGrid.HtmlDataTag.DefaultValue || {};
        vpGrid.HtmlDataTag.DefaultValue.DataSourceType = "web";


        //data tags for security trimming managment
        vpGrid.HtmlDataTag.securityTrimmed = "data-vp-grid-security-trimmed";
        vpGrid.HtmlDataTag.securityTrimmedRoles = "data-vp-grid-security-trimmed-roles";
        vpGrid.HtmlDataTag.securityTrimmedUrl = "data-vp-grid-security-trimmed-url";
        vpGrid.HtmlDataTag.securityTrimmedSequence = "data-vp-grid-security-trimmed-sequence";
        vpGrid.HtmlDataTag.securityTrimmedRolesType = "data-vp-grid-security-trimmed-roles-type";

        //data tags for the creation and the configuration of the grid columns
        vpGrid.HtmlDataTag.ColumnName = "data-vp-grid-column-name";
        vpGrid.HtmlDataTag.ColumnWidth = "data-vp-grid-column-width";
        vpGrid.HtmlDataTag.ColumnFixedWidth = "data-vp-grid-column-fixed-width";
        vpGrid.HtmlDataTag.ColumnHidden = "data-vp-grid-column-hidden";
        vpGrid.HtmlDataTag.ColumnEditable = "data-vp-grid-column-editable";
        vpGrid.HtmlDataTag.ColumnEditType = "data-vp-grid-column-edittype";
        vpGrid.HtmlDataTag.ColumnAlign = "data-vp-grid-column-align";
        vpGrid.HtmlDataTag.ColumnType = "data-vp-grid-column-type";
        vpGrid.HtmlDataTag.ColumnCSS = "data-vp-grid-column-css";
        vpGrid.HtmlDataTag.ColumnFrozen = "data-vp-grid-column-frozen";
        vpGrid.HtmlDataTag.ColumnMinValue = "data-vp-grid-column-min-value";
        vpGrid.HtmlDataTag.ColumnMaxValue = "data-vp-grid-column-max-value";
        vpGrid.HtmlDataTag.ColumnSortable = "data-vp-grid-column-sortable";
        vpGrid.HtmlDataTag.ColumnPlaceholder = "data-vp-grid-column-placeholder";
        vpGrid.HtmlDataTag.ColumnActionType = "data-vp-grid-column-actiontype";
        vpGrid.HtmlDataTag.ColumnLocked = "data-vp-grid-column-locked";
        vpGrid.HtmlDataTag.ColumnInfo = "data-vp-grid-column-info";
        vpGrid.HtmlDataTag.ColumnSummaryAlwaysUpdate = "data-vp-grid-column-summary-always-update";
        vpGrid.HtmlDataTag.ColumnRequired = "data-vp-grid-column-required";

        //data tags for automatic creation and configuration of jQuery-UI widgets
        vpGrid.HtmlDataTag.DialogId = "data-vp-grid-dialog-id";
        vpGrid.HtmlDataTag.UIWidget = "data-vp-grid-ui-widget";
        vpGrid.HtmlDataTag.UIWidgetOptions = "data-vp-grid-ui-widget-options";

        //data tags for remote filtering
        vpGrid.HtmlDataTag.RemoteDataFilterKey = "data-vp-grid-remote-data-filter-key";
        vpGrid.HtmlDataTag.RemoteDataFilterName = "data-vp-grid-remote-data-filter-name";
        vpGrid.HtmlDataTag.RemoteDataFilterOperator = "data-vp-grid-remote-data-filter-operator";

        //data tags for backup/restore/augmentation
        vpGrid.HtmlDataTag.CssToAdd = "data-vp-grid-css-to-add";
        vpGrid.HtmlDataTag.OriginalClassAttributeContent = "data-vp-grid-original-class-attribute-content";

        //public Role attributes used by vpGrid
        // Role attributes are used by vpGrid to locate specific parts of the grid or elements used by the grid.
        vpGrid.HtmlRoleAttribute = vpGrid.HtmlRoleAttribute || {};
        vpGrid.HtmlRoleAttribute.vpGridContainer = "vp-grid-container";
        vpGrid.HtmlRoleAttribute.vpGridBody = "vp-grid-body";
        vpGrid.HtmlRoleAttribute.vpGridSchema = "vp-grid-schema";
        vpGrid.HtmlRoleAttribute.vpGridSchemaColumns = "vp-grid-schema-columns";
        vpGrid.HtmlRoleAttribute.vpGridSchemaCaption = "vp-grid-schema-caption";
        vpGrid.HtmlRoleAttribute.vpGridSchemaColumnsGroup = "vp-grid-schema-columns-group";
        vpGrid.HtmlRoleAttribute.vpGridSchemaStatusBar = "vp-grid-schema-status-bar";
        vpGrid.HtmlRoleAttribute.Titlebar = "vp-grid-dialog-title-bar";
        vpGrid.HtmlRoleAttribute.vpGridModalDialog = "vp-grid-modal-dialog";
        vpGrid.HtmlRoleAttribute.RemoteDataFilter = "vp-grid-remote-data-filter";
        vpGrid.HtmlRoleAttribute.ActiveHeader = "vp-grid-active-header";
        vpGrid.HtmlRoleAttribute.vpGridRibbon = "vp-grid-ribbon";
        vpGrid.HtmlRoleAttribute.vpGridPartialUI = "vp-grid-partial-ui";

        //trace API
        function logExceptionToConsole(ex) {
            try {
                if (ex === undefined) {
                    return;
                }

                if (console === undefined) {
                    return;
                }

                if (console.error === undefined) {
                    return;
                }

                var smalldateTime = new Date().toSmallDateTime();
                var msg = "[" + smalldateTime + "] ";

                if (ex.stack) {
                    msg += ex.stack;
                    console.error(msg);
                    return;
                }

                if (ex.message) {
                    msg += ex.message;
                }

                console.error(msg);

            } catch (e) {
                var msg = e.message;
            }
        }

        function sendExceptionToRemote(ex) {
            try {
                //check if sending messages to remote server is enabled
                if (!vpGridOptions.enableRemoteLogging) {
                    return;
                }

                //get url to be requested
                var crudOperations = vpGridOptions.crudOptions;
                if (isNullOrUndefinedOrEmpty(crudOperations)) {
                    vpGrid.logError({
                        message: "CRUD operations are not defined in the vpGrid Options object. Errors cannot be sent to remote server."
                    });
                    return;
                }

                if (isNullOrUndefinedOrEmpty(crudOperations.trace)) {
                    vpGrid.logError({
                        message: "CRUD option trace is not defined in the vpGrid Options object. Errors cannot be sent to remote server."
                    });
                    return;
                }

                var requestUrl = crudOperations.trace;
                requestUrl += '&error=' + encodeURIComponent(JSON.stringify(ex));
                var img = new Image();
                img.src = requestUrl;

            } catch (e) {
                logExceptionToConsole(e);
            }
        }

        vpGrid.logException = function (ex) {
            /// <signature>
            /// <summary>Log exception on all configured output devices (Console, Remote Server, custom DOM element</summary>
            /// <param name="ex" type="Object">exception object</param>
            /// </signature>
            try {
                logExceptionToConsole(ex);

                sendExceptionToRemote(ex);

                //TODO : log inside specific DOM element

            } catch (e) {
                logExceptionToConsole(e);
            }
        };

        function logErrorToConsole(err) {
            try {
                if (err === undefined) {
                    return;
                }

                if (console === undefined) {
                    return;
                }

                if (console.error === undefined) {
                    return;
                }

                var smalldateTime = new Date().toSmallDateTime();
                var msg = "[" + smalldateTime + "] ";

                if (err.functionName) {
                    msg += "[function: " + err.functionName + "] ";
                }

                if (err.callerName) {
                    msg += "[caller name: " + err.callerName + "] ";
                }

                if (err.message) {
                    msg += err.message;
                }

                if (err.info) {
                    msg += '\n' + err.info;
                }

                //if (err.callerCode) {
                //    msg += "\n[caller code: " + err.callerCode + "] ";
                //}

                console.error(msg);

            } catch (e) {
                logExceptionToConsole(e);
            }
        }

        vpGrid.logError = function (err) {
            /// <signature>
            /// <summary>Log application error on all configured output devices (Console, Remote Server, custom DOM element</summary>
            /// <param name="err" type="Object">literal object that is like { message : "xxx", functionName : "yyy", info : "ttt" }</param>
            /// </signature>
            try {
                // try find caller
                try {
                    var caller = vpGrid.logError.caller;
                    var callerName = caller.name.toString();
                    var callerCode = caller.toString();
                    err.callerName = callerName;
                    err.callerCode = callerCode;

                } catch (e) {

                }

                logErrorToConsole(err);

                //TODO : remote logging

                //TODO : log inside specific DOM element

            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function logAjaxErrorToConsole(xhr, statusMessage, errorMessage) {
            try {
                if (xhr === undefined) {
                    return;
                }

                if (console === undefined) {
                    return;
                }

                if (console.error === undefined) {
                    return;
                }

                var smalldateTime = new Date().toSmallDateTime();
                var msg = "[" + smalldateTime + "] ";
                if (statusMessage) {
                    msg += statusMessage;
                }

                if (errorMessage) {
                    msg += "; " + errorMessage;
                }

                console.error(msg);

            } catch (e) {
                //TODO : log
                var msg = e.message;
            }
        };

        function logAjaxError(xhr, statusMessage, errorMessage) {
            try {
                logAjaxErrorToConsole(xhr, statusMessage, errorMessage);

                //TODO : remote logging

                //TODO : log inside specific DOM element

            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function logAjaxHttpStatusCode(statusCode) {
            try {
                if (isNullOrUndefined(statusCode)) {
                    return;
                }

                var statusErrorMap = {
                    0: "Cross Domain call is rejected by the browser (see CORS configuration)",
                    400: "Server understood the request but request content was invalid.",
                    401: "Unauthorised access.",
                    403: "Forbidden resouce can't be accessed",
                    500: "Internal Server Error.",
                    503: "Service Unavailable"
                };
                var message = "Http status code : " + statusCode + "; ";
                if (statusCode in statusErrorMap) {
                    message += statusErrorMap[statusCode];
                }
                vpGrid.logError({ message: message });

            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function logServerError(response, details, element) {
            try {
                if (isNullOrUndefined(response)) {
                    //TODO : log
                    return;
                }

                var errorMessage = "";
                if (isNotNullOrUndefinedOrEmpty(response.errorMessage)) {
                    errorMessage = response.errorMessage;
                }

                var detailsMessage = "";
                if (isNotNullOrUndefinedOrEmpty(details)) {
                    detailsMessage = details;
                }

                var domHTML = outerHtml(element);

                var message = "Server Error : " + errorMessage + "; " + detailsMessage + "; on element: \n" + domHTML;
                vpGrid.logError({ message: message });

            } catch (e) {
                vpGrid.logException(e);
            }
        };
        // end trace API


        // Javascript Types Extensions
        //TODO : check if prototypes already exist
        //Date extensions
        (function () {
            try {
                var test = new Date();
                if (test.toSmallDateTime) {
                    vpGrid.logError({
                        message: "Date.prototype.toSmallDateTime is already defined. Check that vpGrid is not loaded twice or that any third-party JavaScript library has already defined this method."
                    });
                    return;
                }

                Date.prototype.toSmallDateTime = function () {
                    try {
                        /// <signature>
                        /// <summary>Get the input date in the following format : 'yyyy/mm/dd hh:mm:ss'</summary>
                        /// <returns type="String">Returns the formated date. If something goes wrong an empty string is returned.</returns>
                        /// </signature>
                        var dd = this.getDate();
                        var mm = this.getMonth() + 1;
                        var yyyy = this.getFullYear();
                        var hh = this.getHours();
                        var mn = this.getMinutes();
                        var ss = this.getSeconds();

                        if (dd < 10) {
                            dd = '0' + dd;
                        }
                        if (mm < 10) {
                            mm = '0' + mm;
                        }

                        if (hh < 10) {
                            hh = '0' + hh;
                        }

                        if (mn < 10) {
                            mn = '0' + mn;
                        }

                        if (ss < 10) {
                            ss = '0' + ss;
                        }

                        var now = yyyy + '/' + mm + '/' + dd + ' ' + hh + ':' + mn + ':' + ss;
                        return now;

                    } catch (e) {
                        vpGrid.logException(e);
                        return "";
                    }
                };


                if (test.year) {
                    vpGrid.logError({
                        message: "Date.prototype.year is already defined. Check that vpGrid is not loaded twice or that any third-party JavaScript library has already defined this method."
                    });
                    return;
                }
                Date.prototype.year = function () {
                    try {
                        /// <signature>
                        /// <summary>Get the year of input date.</summary>
                        /// <returns type="Number">Returns the year as a Number. If something goes wrong, NaN is returned.</returns>
                        /// </signature>
                        var yyyy = this.getFullYear();

                        var now = yyyy;
                        return now;

                    } catch (e) {
                        //TODO : log
                        vpGrid.logException(e);
                        return NaN;
                    }
                };


            } catch (e) {
                vpGrid.logException(e);
            }
        })();


        //Number extensions
        (function () {
            try {
                var test = 123.00;
                if (test.isGreaterThan) {
                    vpGrid.logError({
                        message: "Number.prototype.isGreaterThan is already defined. Check that vpGrid is not loaded twice or that any third-party JavaScript library has already defined this method."
                    });
                    return;
                }

                Number.prototype.isGreaterThan = function (value) {
                    try {
                        /// <signature>
                        /// <summary>Check if the input number is greater than value.</summary>
                        /// <param name="value" type="Number">Value to be compared to.</param>
                        /// <returns type="Boolean">Returns true if input number is > value.</returns>
                        /// </signature>

                        if (isNotNumber(value)) {
                            return false;
                        }

                        if (this > value) {
                            return true;
                        }

                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                };


                if (test.isLowerThan) {
                    vpGrid.logError({
                        message: "Number.prototype.isLowerThan is already defined. Check that vpGrid is not loaded twice or that any third-party JavaScript library has already defined this method."
                    });
                    return;
                }

                Number.prototype.isLowerThan = function (value) {
                    try {
                        /// <signature>
                        /// <summary>Check if the input number is lower than value.</summary>
                        /// <param name="value" type="Number">Value to be compared to.</param>
                        /// <returns type="Boolean">Returns true if input number is < value.</returns>
                        /// </signature>

                        if (isNotNumber(value)) {
                            return false;
                        }

                        if (this < value) {
                            return true;
                        }

                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                };

                //hack
                Number.prototype.toFloat = function () {
                    return this;
                }

            } catch (e) {
                vpGrid.logException(e);
            }
        })();

        //Array extensions
        Array.prototype.toUnique = function () {
            try {

                if (this.length === 0) {
                    return this;
                }

                if (this.length === 1) {
                    return this;
                }


                var result = [], map = {}, item;
                var itemCount = this.length;
                for (var i = 0; i < itemCount; i++) {
                    item = this[i];
                    if (!map[item]) {
                        result.push(item);
                        map[item] = true;
                    }
                }

                return result;


            } catch (e) {
                vpGrid.logException(e);
                return this;
            }
        };

        Array.prototype.removeEmptyEntries = function () {
            try {

                if (this.length === 0) {
                    return this;
                }

                var result = [];
                var itemCount = this.length;
                for (var i = 0; i < itemCount; i++) {
                    var item = this[i];
                    if (isNotNullOrUndefinedOrEmpty(item)) {
                        result.push(item);
                    }
                }

                return result;

            } catch (e) {
                vpGrid.logException(e);
                return this;
            }
        };

        Array.prototype.clear = function () {
            try {

                if (this.length === 0) {
                    return this;
                }

                var itemCount = this.length;
                for (var i = 0; i < itemCount; i++) {
                    this.shift();
                }

                return this;

            } catch (e) {
                vpGrid.logException(e);
                return this;
            }
        };

        Array.prototype.pushOnce = function (input) {
            try {

                if (isNullOrUndefinedOrEmpty(input)) {
                    //TODO : log
                    return;
                }

                if (this.length === 0) {
                    this.push(input);
                    return;
                }

                var itemCount = this.length;
                for (var i = 0; i < itemCount; i++) {
                    var item = this[i];
                    if (item === input) {
                        return;
                    }
                }
                this.push(input);

            } catch (e) {
                vpGrid.logException(e);
                return this;
            }
        };

        Array.prototype.isEmpty = function () {
            try {

                if (this.length === 0) {
                    return true;
                }

                var itemCount = this.length;
                for (var i = 0; i < itemCount; i++) {
                    var item = this[i];
                    if (isNotNullOrUndefinedOrEmpty(item)) {
                        return false;
                    }
                }

                return true;

            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        };

        Array.prototype.getValueOfKey = function (keyName) {
            /// <signature>
            /// <summary>Get the value of the input key.The array must be a collection of key/value pairs : [ {key:xxx,value:yyy}, ...]</summary>
            /// <param name="keyName" type="String">Value of the key to search in the dictionnary</param>
            /// <returns type="Object">Returns the content of the value property when the key is found. If key not found it returns undefined.</returns>
            /// </signature>
            try {

                if (this.length === 0) {
                    return undefined;
                }

                if (isNotString(keyName)) {
                    vpGrid.logError({
                        functionName: "getValueOfKey",
                        message: "input keyName is not a valid string."
                    });
                    return undefined;
                }

                var itemCount = this.length;
                for (var i = 0; i < itemCount; i++) {
                    var item = this[i];

                    var key = item.key;
                    if (key === keyName) {
                        return item.value;
                    }

                }

                return undefined;

            } catch (e) {
                vpGrid.logException(e);
                return undefined;
            }
        };

        Array.prototype.addRangeOfIntegers = function (minValue, maxValue) {
            /// <signature>
            /// <summary>Adds a ranges of consecutive integers in the input array.</summary>
            /// <param name="minValue" type="Int">Start integer value to add in the array.</param>
            /// <param name="maxValue" type="Int">Last integer value to add in the array.</param>
            /// <returns type="Array">Returns input array filled with input values starting from minValue up to maxValue.</returns>
            /// </signature>
            try {
                if (isNotInt(minValue)) {
                    //TODO : log
                    return;
                }

                if (isNotInt(maxValue)) {
                    //TODO : log
                    return;
                }

                if (minValue === maxValue) {
                    this.push(minValue);
                    return;
                }

                if (minValue > maxValue) {
                    //TODO : log
                    return;
                }


                for (var i = minValue; i <= maxValue; i++) {
                    this.push(i);
                }

            } catch (e) {
                vpGrid.logException(e);
                return this;
            }
        };

        Array.prototype.sum = function () {
            /// <signature>
            /// <summary>Compute the sum of all items in input array.Each item in this array may be a number or maybe a string.</summary>
            /// <returns type="Number">Returns the sum of all items in the array. Returns zero if something goes wrong.</returns>
            /// </signature>
            try {
                var sum = 0;
                var itemCount = this.length;
                for (var i = 0; i < itemCount; i++) {
                    var item = this[i];
                    if (isNotNumber(item)) {
                        continue;
                    }
                    var itemValue = item.toFloat();

                    if (isNaN(itemValue)) {
                        continue;
                    }
                    sum += itemValue;
                }
                

                return sum;

            } catch (e) {
                vpGrid.logException(e);
                return 0;
            }
        };

        Array.prototype.minus = function (input) {
            /// <signature>
            /// <summary>Compute the difference of all items between this array and input array.Each item in both arrays may be a number or maybe a string.</summary>
            /// <param name="input" type="Array">Right operand of the minus operation. Shaould be an array of same size as this array.</param>
            /// <returns type="Array">Returns anew array that contains the difference of all items. Returns zero if something goes wrong.</returns>
            /// </signature>
            try {
                var diffArray = [];
                var itemCount = this.length;
                for (var i = 0; i < itemCount; i++) {
                    var item1 = this[i];
                    var item2 = input[i];
                    if (isNotNumber(item1)) {
                        diffArray.push(NaN);
                        continue;
                    }
                    if (isNotNumber(item2)) {
                        diffArray.push(NaN);
                        continue;
                    }
                    var item1Value = item1.toFloat();
                    var item2Value = item2.toFloat();

                    if (isNaN(item1Value)) {
                        diffArray.push(NaN);
                        continue;
                    }

                    if (isNaN(item2Value)) {
                        diffArray.push(NaN);
                        continue;
                    }
                    diffArray.push(item1Value - item2Value);
                }


                return diffArray;

            } catch (e) {
                vpGrid.logException(e);
                return [];
            }
        };

        Array.prototype.duplicate = function (input) {
            /// <signature>
            /// <summary>Duplicate input array.</summary>
            /// <param name="input" type="Array">Array to be duplicated</param>
            /// <returns type="Array">Returns a new array that is a copy of input array.</returns>
            /// </signature>
            try {
                var duplicatedArray = [];
                var itemCount = this.length;
                for (var i = 0; i < itemCount; i++) {
                    var item = this[i];
                    var duplicatedItem = item;
                    //TODO : make a copy of item1 if it is a lietarl object

                    duplicatedArray.push(duplicatedItem);
                }

                return duplicatedArray;

            } catch (e) {
                vpGrid.logException(e);
                return [];
            }
        };

        // end Array extensions



        //String extensions
        String.prototype.isString = function () {
            return true;
        };

        String.prototype.isNullOrEmpty = function () {
            try {
                if (this === null) {
                    return true;
                }

                if (this === undefined) {
                    return true;
                }

                if (this.length === undefined) {
                    return true;
                }

                if (this.length === 0) {
                    return true;
                }

                return false;

            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        };

        String.prototype.isNullOrEmptyOrWhitespace = function () {
            try {
                if (this === null) {
                    return true;
                }

                if (this === undefined) {
                    return true;
                }

                if (this.length === undefined) {
                    return true;
                }

                if (this.length === 0) {
                    return true;
                }

                if (this.trim === undefined) {
                    String.prototype.trim = function () { return this.replace(/^\s+|\s+$/g, ''); };
                }

                var trimedInput = this.trim();

                if (trimedInput === null) {
                    return true;
                }

                if (trimedInput === undefined) {
                    return true;
                }

                if (trimedInput.length === undefined) {
                    return true;
                }

                if (trimedInput.length === 0) {
                    return true;
                }

                return false;

            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        };

        String.prototype.isNotNullOrEmptyOrWhitespace = function () {
            return this.isNullOrEmptyOrWhitespace() === false;
        };

        String.prototype.toEncodedSymbols = function () {
            try {

                if (this.isNullOrEmptyOrWhitespace()) {
                    return "";
                }

                var encoded = this.replace("ô", "&#244;");
                return encoded;

            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return this;
            }
        };

        String.prototype.toEncodedHTML = function () {
            try {

                if (this.isNullOrEmptyOrWhitespace()) {
                    return "";
                }

                var htmlEncodedInput = $('<div/>').text(this).html();
                //htmlEncodedInput = htmlEncodedInput.toEncodedSymbols();

                return htmlEncodedInput;

            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return this;
            }
        };

        String.prototype.toArray = function (splitter) {
            try {
                if (this.isNullOrEmptyOrWhitespace()) {
                    return [];
                }
                if (isNullOrUndefinedOrEmpty(splitter)) {
                    splitter = ",";
                }

                var splittedArray = this.split(splitter);

                if (isNullOrUndefinedOrEmpty(splittedArray)) {
                    return [];
                }

                // trim every item and remove empty items
                var itemCount = splittedArray.length;
                var normalizedArray = [];
                for (var i = 0; i < itemCount; i++) {
                    var item = splittedArray[i];
                    item = $.trim(item);

                    if (isNotString(item)) {
                        continue;
                    }

                    if (item.isNullOrEmptyOrWhitespace()) {
                        continue;
                    }
                    normalizedArray.push(item);
                }

                return normalizedArray;

            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return [];
            }
        };

        String.prototype.toInt = function () {
            try {
                if (this.isNullOrEmptyOrWhitespace()) {
                    return NaN;
                }

                var intValue = parseInt(this, 10);

                return intValue;

            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return NaN;
            }
        };

        String.prototype.isInt = function () {
            try {
                if (this.isNullOrEmptyOrWhitespace()) {
                    return false;
                }

                if (isNaN(this)) {
                    return false;
                }
                //TODO : remove all spaces
                //TODO : check for non numeric characters

                return true;

            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return false;
            }
        };

        String.prototype.isFloat = function () {
            try {
                if (this.isNullOrEmptyOrWhitespace()) {
                    return false;
                }

                if (isNaN(this)) {
                    return false;
                }

                return true;

            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return false;
            }
        };

        String.prototype.toFloat = function () {
            try {
                if (this.isNullOrEmptyOrWhitespace()) {
                    return NaN;
                }

                var floatValue = parseFloat(this);

                return floatValue;

            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return NaN;
            }
        };

        String.prototype.multipliedBy = function (value) {
            try {
                if (this.isNullOrEmptyOrWhitespace()) {
                    return NaN;
                }

                if (isNotNumber(value)) {
                    return NaN;
                }

                if (isNotNumber(this)) {
                    return NaN;
                }

                var val1 = this.toFloat();
                var val2 = value;
                if (val2.toFloat) {
                    val2 = val2.toFloat();
                }

                var result = val1 * val2;
                return result;

            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return NaN;
            }
        };

        String.prototype.startsWith = function (prefix) {
            try {
                if (this.isNullOrEmptyOrWhitespace()) {
                    return false;
                }

                if (isNotString(prefix)) {
                    return false;
                }

                if (prefix.length > this.length) {
                    return false;
                }

                var thisPrefix = this.substring(0, prefix.length);
                if (thisPrefix === prefix) {
                    return true;
                }

                return false;

            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return false;
            }
        };

        String.prototype.removePrefix = function (prefix) {
            try {

                if (this.isNullOrEmptyOrWhitespace()) {
                    return "";
                }

                if (isNotString(prefix)) {
                    return this;
                }

                if (prefix.isNullOrEmptyOrWhitespace()) {
                    return this;
                }

                if (prefix.length > this.length) {
                    return this;
                }

                if (this.startsWith(prefix)) {
                    var result = this.substring(prefix.length);
                    return result;
                }

                return this;

            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return this;
            }
        };

        String.prototype.contains = function (search) {
            try {
                if (this.isNullOrEmptyOrWhitespace()) {
                    return false;
                }

                if (isNotString(search)) {
                    return false;
                }

                if (search.length > this.length) {
                    return false;
                }

                var index = this.indexOf(search);
                if (index !== -1) {
                    return true;
                }

                return false;

            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        };

        String.prototype.doesNotContain = function (search) {
            return this.contains(search) === false;
        };

        String.prototype.isInArray = function (inputArray) {
            try {

                if (this.isNullOrEmptyOrWhitespace()) {
                    return false;
                }

                if (isNotArray(inputArray)) {
                    return false;
                }

                var itemCount = inputArray.length;

                if (itemCount === 0) {
                    return false;
                }

                var thisValue = this.toString();

                for (var i = 0; i < itemCount; i++) {
                    if (inputArray[i] === thisValue) {
                        return true;
                    }

                }

                return false;

            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        };

        String.prototype.isNotInArray = function (inputArray) {
            return this.isInArray(inputArray) === false;
        };

        String.prototype.replaceAll = function (stringToSearch, stringToReplace) {
            try {

                if (this.isNullOrEmptyOrWhitespace()) {
                    return "";
                }

                if (isNotString(stringToSearch)) {
                    return this;
                }

                if (isNotString(stringToReplace)) {
                    return this;
                }

                if (stringToSearch.isNullOrEmpty()) {
                    return this;
                }

                if (stringToSearch.length > this.length) {
                    return this;
                }

                var result = this;
                var length0 = result.length;
                for (var i = 0; i < 100; i++) {
                    if (result.doesNotContain(stringToSearch)) {
                        return result.toString();
                    }
                    result = result.replace(stringToSearch, stringToReplace);
                    var length = result.length;
                    if (length === length0) {
                        return result.toString();
                    }

                    length0 = length;
                }

                return this;

            } catch (e) {
                vpGrid.logException(e);
                return this;
            }
        };

        String.prototype.leafName = function () {
            /// <signature>
            /// <summary>Get the leaf name on a string that represents an Url</summary>
            /// </signature>
            try {

                if (this.isNullOrEmptyOrWhitespace()) {
                    return "";
                }

                var inputArray = this.toArray("/");
                if (isNullOrUndefinedOrEmpty(inputArray)) {
                    return this;
                }

                var leafName = inputArray.pop();

                return leafName;

            } catch (e) {
                vpGrid.logException(e);
                return this;
            }
        };

        String.prototype.isCustomPropertyOf = function (input) {
            /// <signature>
            /// <summary>Checks if this string is the name of an existing custom property within input object </summary>
            /// <param name="input" type="Object">Object in which to search for the custom property.</param>
            /// <returns type="Boolean">Returns true if a custom property with the same name exists in the input object.</returns>
            /// </signature>
            try {

                if (input === null) {
                    return false;
                }

                if (input === undefined) {
                    return false;
                }

                if (input.hasOwnProperty === undefined) {
                    return false;
                }

                if (typeof input.hasOwnProperty !== "function") {
                    return false;
                }

                if (input.hasOwnProperty(this)) {
                    return true;
                }

                return false;

            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        };

        String.prototype.isNotCustomPropertyOf = function (input) {
            return this.isCustomPropertyOf(input) === false;
        };

        // end Javascript Types Extensions

        // jQuery extensions
        $.fn.extend({
            isNot: function (selector) {
                return this.is(selector) === false;
            }
        });

        $.fn.extend({
            notFound: function () {
                try {
                    if (this === null) {
                        return true;
                    }

                    if (this === undefined) {
                        return true;
                    }

                    if (this.length === undefined) {
                        return true;
                    }

                    if (this.length === 0) {
                        return true;
                    }

                    return false;

                } catch (e) {
                    //TODO : log
                    vpGrid.logException(e);
                    return false;
                }
            }
        });

        $.fn.extend({
            found: function () {
                try {
                    if (this === null) {
                        return false;
                    }

                    if (this === undefined) {
                        return false;
                    }

                    if (this.length === undefined) {
                        return false;
                    }

                    if (this.length === 0) {
                        return false;
                    }

                    return true;

                } catch (e) {
                    //TODO : log
                    vpGrid.logException(e);
                    return false;
                }
            }
        });

        $.fn.extend({
            isCheckbox: function () {
                try {
                    if (this.notFound()) {
                        return false;
                    }

                    if (this.is(':checkbox')) {
                        return true;
                    }

                    return false;

                } catch (e) {
                    vpGrid.logException(e);
                    return false;
                }
            }
        });

        $.fn.extend({
            isNotCheckbox: function () {
                return this.isCheckbox === false;
            }
        });


        $.fn.extend({
            isUncheked: function () {
                try {
                    if (this.notFound()) {
                        return true;
                    }

                    if (this.is(':checked')) {
                        return true;
                    }

                    return false;

                } catch (e) {
                    vpGrid.logException(e);
                    return false;
                }
            }
        });

        $.fn.extend({
            isInputText: function () {
                try {
                    if (this.notFound()) {
                        return false;
                    }

                    if (this.is('input:text')) {
                        return true;
                    }

                    if (this.is('input:password')) {
                        return true;
                    }

                    //if (this.is('input:email')) {
                    //    return true;
                    //}

                    return false;

                } catch (e) {
                    vpGrid.logException(e);
                    return false;
                }
            }
        });

        $.fn.extend({
            toBooleanOrDefaultFromAttribute: function (attributeName, defaultValue) {
                try {
                    if (this === null) {
                        return defaultValue;
                    }

                    if (this === undefined) {
                        return defaultValue;
                    }

                    if (this.length === undefined) {
                        return defaultValue;
                    }

                    if (this.length === 0) {
                        return defaultValue;
                    }

                    if (isNotString(attributeName)) {
                        return defaultValue;
                    }

                    var attributeValue = this.attr(attributeName);
                    if (isNullOrUndefinedOrEmpty(attributeValue)) {
                        return defaultValue;
                    }

                    if (isNotString(attributeValue)) {
                        return defaultValue;
                    }

                    attributeValue = attributeValue.trim();

                    if (attributeValue.isNullOrEmptyOrWhitespace()) {
                        return defaultValue;
                    }

                    if (attributeValue === "true") {
                        return true;
                    }

                    return false;

                } catch (e) {
                    vpGrid.logException(e);
                    return defaultValue;
                }
            }
        });

        $.fn.extend({
            toIntOrDefaultFromAttribute: function (attributeName, defaultValue) {
                /// <signature>
                /// <summary>Get the attribute value as an integer</summary>
                /// <param name="attributeName" type="String">Name of the tag attribute</param>
                /// <param name="defaultValue" type="Number">Value to return if attribute is not found or is not in valid format</param>
                /// <returns type="Number">Returns the found attribute value or the defaultValue if attribute is not found or its value is not valid.</returns>
                /// </signature>
                try {
                    if (this === null) {
                        return defaultValue;
                    }

                    if (this === undefined) {
                        return defaultValue;
                    }

                    if (this.length === undefined) {
                        return defaultValue;
                    }

                    if (this.length === 0) {
                        return defaultValue;
                    }

                    if (isNotString(attributeName)) {
                        return defaultValue;
                    }

                    var attributeValue = this.attr(attributeName);
                    if (isNullOrUndefinedOrEmpty(attributeValue)) {
                        return defaultValue;
                    }

                    if (isNotString(attributeValue)) {
                        return defaultValue;
                    }

                    if (isNotNumber(attributeValue)) {
                        return defaultValue;
                    }

                    var intValue = attributeValue.toInt();

                    return intValue;

                } catch (e) {
                    vpGrid.logException(e);
                    return defaultValue;
                }
            }
        });

        $.fn.extend({
            toStringOrDefaultFromAttribute: function (attributeName, defaultValue) {
                try {
                    if (this === null) {
                        return defaultValue;
                    }

                    if (this === undefined) {
                        return defaultValue;
                    }

                    if (this.length === undefined) {
                        return defaultValue;
                    }

                    if (this.length === 0) {
                        return defaultValue;
                    }

                    if (isNotString(attributeName)) {
                        return defaultValue;
                    }

                    var attributeValue = this.attr(attributeName);
                    if (isNotString(attributeValue)) {
                        return defaultValue;
                    }

                    //trim the value;
                    attributeValue = attributeValue.trim();

                    if (attributeValue.isNullOrEmptyOrWhitespace()) {
                        return defaultValue;
                    }

                    return attributeValue;

                } catch (e) {
                    vpGrid.logException(e);
                    return defaultValue;
                }
            }
        });

        $.fn.extend({
            toEncodedHTML: function () {
                return this.each(function () {
                    try {

                        var jqElement = $(this);

                        // get the text inside this HTML tag
                        var rawText = jqElement.text();
                        var encodedText = rawText.toEncodedHTML();
                        jqElement.html(encodedText);

                    } catch (e) {
                        //TODO : log
                        vpGrid.logException(e);

                    }
                });

            }
        });

        $.fn.extend({
            hideEx: function () {
                return this.each(function () {
                    try {
                        var jqElement = $(this);

                        // apply css class that will hide the element
                        jqElement.addClass("vp-grid-hidden");

                        if (jqElement.is("option")) {
                            jqElement.attr('disabled', 'true');

                            //TODO : backup current selected option in select tag

                            jqElement.removeAttr("selected");
                        }


                    } catch (e) {
                        vpGrid.logException(e);
                    }

                });
            }
        });

        $.fn.extend({
            showEx: function () {
                return this.each(function () {
                    try {
                        var jqElement = $(this);

                        // apply css class that will hide the element
                        jqElement.removeClass("vp-grid-hidden");

                        if (jqElement.is("option")) {
                            jqElement.removeAttr('disabled');
                            // TODO : restore current selected option in select tag
                        }


                    } catch (e) {
                        //TODO : log
                        vpGrid.logException(e);

                    }

                });
            }
        });

        $.fn.extend({
            saveOriginalClassAttributeContent: function () {
                return this.each(function () {
                    try {
                        var jqElement = $(this);

                        if (jqElement.notFound()) {
                            vpGrid.logError({
                                functionName: "saveOriginalClassAttributeContent",
                                message: "Selector not found : " + jqElement.selector
                            });
                            return;
                        }

                        var originalContent = jqElement.toStringOrDefaultFromAttribute(
                                    vpGrid.HtmlDataTag.OriginalClassAttributeContent,
                                    "");

                        if (originalContent.isNotNullOrEmptyOrWhitespace()) {
                            // the save operation has already been done
                            return;
                        }

                        var classAttributeContent = jqElement.toStringOrDefaultFromAttribute("class", "");
                        if (classAttributeContent.isNullOrEmptyOrWhitespace()) {
                            classAttributeContent = "_"; // special hack in case jqElement has no class attribute
                        }

                        jqElement.attr(vpGrid.HtmlDataTag.OriginalClassAttributeContent, classAttributeContent);

                    } catch (e) {
                        vpGrid.logException(e);
                    }

                });
            }
        });

        $.fn.extend({
            restoreOriginalClassAttributeContent: function () {
                return this.each(function () {
                    try {
                        var jqElement = $(this);

                        if (jqElement.notFound()) {
                            vpGrid.logError({
                                functionName: "restoreOriginalClassAttributeContent",
                                message: "Selector not found : " + jqElement.selector
                            });
                            return;
                        }

                        var originalContent = jqElement.toStringOrDefaultFromAttribute(
                                    vpGrid.HtmlDataTag.OriginalClassAttributeContent,
                                    "");

                        jqElement.attr("class", originalContent);

                    } catch (e) {
                        vpGrid.logException(e);
                    }

                });
            }
        });

        $.fn.extend({
            openServerSideDialog: function (widthPercentage, heightPercentage) {
                /// <signature>
                /// <summary>Load an external url within an iframe as a modal pop-up. The iframe is wrapped in a jQuery-ui widget dialog modal window.</summary>
                /// <param name="widthPercentage" type="Number">width of the iframe expressed as a percentage of the current browser window width. The value must be between 0.1 and 0.9. If no value is supplied then default is 0.9</param>
                /// <param name="heightPercentage" type="Number">height of the iframe expressed as a percentage of the current browser window height. The value must be between 0.1 and 0.9. If no value is supplied then default is 0.9</param>
                /// </signature>
                try {
                    var jqElement = $(this);
                    if (jqElement.notFound()) {
                        vpGrid.logError({
                            message: "selector not found : " + jqElement.selector,
                            functionName: "openServerSideDialog"
                        });
                        return;
                    }

                    var windowSize = {
                        width: $(window).width(),
                        height: $(window).height()
                    };

                    //get the iframe url:
                    var iframeUrl = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.Url, "");

                    if (iframeUrl.isNullOrEmptyOrWhitespace()) {
                        var domElement = jqElement.html();
                        vpGrid.logError({
                            functionName: "openServerSideDialog",
                            message: "data attribute : " + vpGrid.HtmlDataTag.Url + " is not defined on element : \n" + domElement
                        });
                        return;
                    }

                    //get input parameters
                    var widthCoeff = 0.9;
                    if (isNumber(widthPercentage)) {
                        widthCoeff = widthPercentage;
                    }

                    var heightCoeff = 0.9;
                    if (isNumber(heightCoeff)) {
                        heightCoeff = heightPercentage;
                    }

                    var iframe = $('<iframe>', {
                        frameborder: 0,
                        scrolling: 'no',
                        width: windowSize.width * widthCoeff,
                        height: windowSize.height * heightCoeff,
                        src: iframeUrl
                    });

                    //change the dialog options
                    jqElement.dialog('option', {
                        width: "auto",
                        height: "auto"
                    });


                    //empty current content of the dialog
                    jqElement.html("");

                    iframe.appendTo(jqElement);
                    jqElement.dialog('open');

                } catch (e) {
                    vpGrid.logException(e);

                }
            }
        });

        $.fn.extend({
            openClientSideDialog: function (position, widthPercentage, heightPercentage) {
                /// <signature>
                /// <summary>Open a jQuery-ui widget dialog modal window.</summary>
                /// <param name="widthPercentage" type="Number">width of the iframe expressed as a percentage of the current browser window width. The value must be between 0.1 and 0.9. If no value is supplied then default is 0.9</param>
                /// <param name="heightPercentage" type="Number">height of the iframe expressed as a percentage of the current browser window height. The value must be between 0.1 and 0.9. If no value is supplied then default is 0.9</param>
                /// </signature>
                try {
                    var jqElement = $(this);
                    if (jqElement.notFound()) {
                        vpGrid.logError({
                            message: "selector not found : " + jqElement.selector,
                            functionName: "openServerSideDialog"
                        });
                        return;
                    }

                    var windowSize = {
                        width: $(window).width(),
                        height: $(window).height()
                    };

                    //get input parameters
                    var widthCoeff = 0.9;
                    if (isNumber(widthPercentage)) {
                        widthCoeff = widthPercentage;
                    }

                    var heightCoeff = 0.9;
                    if (isNumber(heightCoeff)) {
                        heightCoeff = heightPercentage;
                    }

                    //change the dialog options
                    jqElement.dialog('option', {
                        width: "auto",
                        height: "auto"
                    });

                    if (isNotNullOrUndefinedOrEmpty(position)) {
                        jqElement.dialog('option', 'position', position);
                    }


                    var jqTitlebarContent = jqElement.closest('div.ui-dialog').find('div.ui-dialog-titlebar span.ui-dialog-title');
                    // check if there is custom content to inject in the title bar

                    if (jqTitlebarContent.notFound()) {
                        vpGrid.logError({
                            message: "Selector not found : '" + jqTitlebarContent.selector + "'",
                            functionName: "openClientSideDialog",
                            info: "The title cannot be modified on modal dialog element : \n" + outerHtml(jqElement[0])

                        });
                    }

                    var customTitleSelector = "div[role=" + vpGrid.HtmlRoleAttribute.Titlebar + "]";
                    var customTitle = jqElement.find(customTitleSelector);

                    if (customTitle.found()) {
                        customTitle.detach();
                        jqTitlebarContent.html("");
                        customTitle.appendTo(jqTitlebarContent);
                        customTitle.removeClass("vp-grid-hidden");

                        // add special class to select element so that it is selectable
                        customTitle.find('select').addClass('ui-dialog-content');
                    }

                    // reset all validation error messages coming from previous usage
                    jqElement.resetValidationErrors();

                    jqElement.dialog('open');

                } catch (e) {
                    vpGrid.logException(e);

                }
            }
        });

        $.fn.extend({
            openClientSideDialogWithSelectedItem: function (position, widthPercentage, heightPercentage) {
                /// <signature>
                /// <summary>Open a jQuery-ui widget dialog modal window.
                ///         Input controls on this dialog are filled with the data coming from the selected item in the grid.
                ///         The databinding is done through the data-tag attribute : data-vp-grid-column-name
                ///</summary>
                /// <param name="widthPercentage" type="Number">width of the iframe expressed as a percentage of the current browser window width. The value must be between 0.1 and 0.9. If no value is supplied then default is 0.9</param>
                /// <param name="heightPercentage" type="Number">height of the iframe expressed as a percentage of the current browser window height. The value must be between 0.1 and 0.9. If no value is supplied then default is 0.9</param>
                /// </signature>
                try {
                    var jqElement = $(this);
                    if (jqElement.notFound()) {
                        vpGrid.logError({
                            message: "selector not found : " + jqElement.selector,
                            functionName: "openServerSideDialog"
                        });
                        return;
                    }

                    var windowSize = {
                        width: $(window).width(),
                        height: $(window).height()
                    };

                    //get input parameters
                    var widthCoeff = 0.9;
                    if (isNumber(widthPercentage)) {
                        widthCoeff = widthPercentage;
                    }

                    var heightCoeff = 0.9;
                    if (isNumber(heightCoeff)) {
                        heightCoeff = heightPercentage;
                    }

                    //change the dialog options
                    jqElement.dialog('option', {
                        width: "auto",
                        height: "auto"
                    });

                    if (isNotNullOrUndefinedOrEmpty(position)) {
                        jqElement.dialog('option', 'position', position);
                    }

                    // get the data row
                    var dataRow = JQGrid.selectedRowData();

                    var jqTitlebarContent = jqElement.closest('div.ui-dialog').find('div.ui-dialog-titlebar span.ui-dialog-title');
                    // check if there is custom content to inject in the title bar

                    if (jqTitlebarContent.notFound()) {
                        vpGrid.logError({
                            message: "Selector not found : '" + jqTitlebarContent.selector + "'",
                            functionName: "openClientSideDialogWithSelectedItem",
                            info: "The title cannot be modified on modal dialog element : \n" + outerHtml(jqElement[0])

                        });
                    }

                    var customTitleSelector = "div[role=" + vpGrid.HtmlRoleAttribute.Titlebar + "]";
                    var customTitle = jqElement.find(customTitleSelector);

                    
                    if (customTitle.notFound()) {
                        //the title content has been moved from its orginal place in the DOM when the above code has run one time
                        customTitle = jqElement.closest('div.ui-dialog').find(customTitleSelector);
                    }

                    if (customTitle.found()) {
                        customTitle.detach();
                        jqTitlebarContent.html("");
                        customTitle.appendTo(jqTitlebarContent);
                        customTitle.fillWithDataRow(dataRow);
                        customTitle.removeClass("vp-grid-hidden");

                        // add special class to select element so that it is selectable
                        customTitle.find('select').addClass('ui-dialog-content');
                    }

                    // check if the dialog contains a form element
                    // reset all validation error messages coming from previous usage
                    jqElement.resetValidationErrors();
                    jqElement.fillWithDataRow(dataRow);

                    jqElement.dialog('open');
                    return this;

                } catch (e) {
                    vpGrid.logException(e);
                    return this;
                }
            }
        });



        $.fn.extend({
            fillWithDataRow: function (dataRow, raiseErrorOnNotFound) {
                /// <signature>
                /// <summary>Input controls and other html elements tagged are filled with the input jqGrid row data.
                ///         The databinding is done through the data-tag attribute : data-vp-grid-column-name
                ///</summary>
                /// <param name="dataRow" type="Object">Literal object. The properties of this object must match the data-vp-grid-column-name value </param>
                /// <param name="raiseErrorOnNotFound" type="Boolean">If true and no HTLM element with the data attribute data-vp-grid-column-name has been found then an error is raised. </param>

                /// </signature>
                try {
                    var jqElement = $(this);
                    if (jqElement.notFound()) {
                        vpGrid.logError({
                            message: "selector not found : " + jqElement.selector,
                            functionName: "fillWithRowData"
                        });
                        return;
                    }

                    if (isNullOrUndefinedOrEmpty(raiseErrorOnNotFound)) {
                        raiseErrorOnNotFound = true;
                    }

                    //fill input element from selected item
                    var inputFieldSelector = "[" + vpGrid.HtmlDataTag.ColumnName + "]";
                    var jqInputFields = jqElement.find(inputFieldSelector);

                    if (jqInputFields.notFound() && raiseErrorOnNotFound === true) {
                        vpGrid.logError({
                            functionName: "fillWithRowData",
                            message: "Cannot find input fields with selector : '" + inputFieldSelector + "'",
                            info: "Check that all input fields is tagged with the html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'"
                        });
                        return this;
                    }

                    var fieldsCount = jqInputFields.length;
                    for (var i = 0; i < fieldsCount; i++) {
                        var inputField = jqInputFields[i];
                        var jqInputField = $(inputField);
                        var colName = jqInputField.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnName, "");
                        var importColumnValue = jqInputField.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.ImportColumnValue, true);

                        if (importColumnValue === false) {
                            continue;
                        }

                        if (colName.isNullOrEmptyOrWhitespace()) {
                            vpGrid.logError({
                                functionName: "openClientSideDialogWithSelectedItem",
                                message: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " is not correctly setup on element :\n" + outerHtml(inputField),
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " must be the name of a column"
                            });
                            continue;
                        }

                        if (JQGrid.colDoesNotExist(colName)) {
                            vpGrid.logError({
                                functionName: "openClientSideDialogWithSelectedItem",
                                message: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " is not correctly setup on element :\n" + outerHtml(inputField),
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " must be the name of an existing column."
                            });
                            continue;
                        }

                        var inputValue = dataRow[colName];
                        if (inputValue === undefined) {
                            inputValue = "";
                        }
                        jqInputField.val(inputValue);
                        //if input is a select, take only the displayed value
                        //TODO : create a keyValueFormatter to be able to handle the selected key directly
                        if (jqInputField.is('select')) {
                            jqInputField.setSelectedOptionWithText(inputValue);
                        }

                        if (jqInputField.is('span')) {
                            jqInputField.html("");
                            jqInputField.html(inputValue);
                        }

                    }//end for (var i = 0; i < fieldsCount; i++) 

                    return this;

                } catch (e) {
                    vpGrid.logException(e);
                    return this;
                }
            }
        });

        $.fn.extend({
            insertNewRowFromThisForm: function (pos) {
                /// <signature>
                /// <summary>Insert a new row in the grid from this form element.</summary>
                /// <param name="pos" type="String">Position of insertion in the grid. Valid values are : 'last' and 'first'</param>
                /// <returns type="void"></returns>
                /// </signature>
                try {
                    if (this === null) {
                        return this;
                    }

                    if (this === undefined) {
                        return this;
                    }

                    if (this.length === undefined) {
                        return this;
                    }

                    if (this.length === 0) {
                        return this;
                    }

                    if (isNullOrUndefinedOrEmpty(pos)) {
                        pos = 'last';
                    }

                    //if (this.isNot('form')) {
                    //    vpGrid.logError({
                    //        functionName: "insertNewRow",
                    //        message: "This method should be called on a form element.",
                    //        info: "This method has been called on element :\n" + outerHtml(this[0])
                    //    });
                    //    return this;
                    //}

                    var inputFieldSelector = "[" + vpGrid.HtmlDataTag.ColumnName + "]";
                    var jqInputFields = this.find(inputFieldSelector);

                    if (jqInputFields.notFound()) {
                        vpGrid.logError({
                            functionName: "insertNewRow",
                            message: "Cannot find input fields with selector : '" + inputFieldSelector + "'",
                            info: "Check that all input fields is tagged with the html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'"
                        });
                        return this;
                    }


                    var fieldsCount = jqInputFields.length;
                    var dataRow = {};
                    for (var i = 0; i < fieldsCount; i++) {
                        var element = jqInputFields[i];
                        var jqElement = $(element);
                        var colName = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnName, "");
                        if (colName.isNullOrEmptyOrWhitespace()) {
                            vpGrid.logError({
                                functionName: "insertNewRow",
                                message: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " is not correctly setup on element :\n" + outerHtml(element),
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " must be the name of a column"
                            });
                            continue;
                        }

                        if (JQGrid.colDoesNotExist(colName)) {
                            vpGrid.logError({
                                functionName: "insertNewRow",
                                message: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " is not correctly setup on element :\n" + outerHtml(element),
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " must be the name of an existing column."
                            });
                            continue;
                        }

                        var inputValue = jqElement.val();
                        //if input is a select, take only the displayed value
                        //TODO : create a keyValueFormatter to be able to handle the selected key directly
                        if (jqElement.is('select')) {
                            var jqSelectedOption = jqElement.find('option:selected');
                            inputValue = jqSelectedOption.text();
                        }

                        dataRow[colName] = inputValue;

                    }//end for (var i = 0; i < fieldsCount; i++) 


                    //check if a key has been setup on the Key column
                    var keyColumnName = JQGrid.keyColumnName();
                    if (isNullOrUndefinedOrEmpty(keyColumnName)) {
                        vpGrid.logError({
                            functionName: "insertNewRow",
                            message: "",
                            info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " must be the name of an existing column."
                        });
                        // dynamically add a property to hold our own client primary key
                        dataRow['clientId'] = 'clientId' + vpGrid.guid++;
                    }

                    if (isNotNullOrUndefinedOrEmpty(keyColumnName)) {
                        dataRow[keyColumnName] = 'clientId' + vpGrid.guid++;
                    }

                    //check if deleteActionValidator has been setup
                    var isDeletableColName = JQGrid.deleteActionValidatorColumnName();
                    if (isNotNullOrUndefinedOrEmpty(isDeletableColName)) {
                        dataRow[isDeletableColName] = true;
                    }

                    vpGrid.insertNewRow(dataRow, pos);
                    return this;

                } catch (e) {
                    vpGrid.logException(e);
                    return this;
                }
                
            }
        });










        $.fn.extend({
            updateRowFromThisForm: function (params) {
                /// <signature>
                /// <summary>Insert a new row in the grid from this form element.</summary>
                /// <param name="params" type="Object">Object literal to be sent to the server</param>
                /// <returns type="void"></returns>
                /// </signature>
                try {
                    if (this === null) {
                        return this;
                    }

                    if (this === undefined) {
                        return this;
                    }

                    if (this.length === undefined) {
                        return this;
                    }

                    if (this.length === 0) {
                        return this;
                    }

                    if (isNullOrUndefinedOrEmpty(params)) {
                        params = {};
                    }

                    //if (this.isNot('form')) {
                    //    vpGrid.logError({
                    //        functionName: "insertNewRow",
                    //        message: "This method should be called on a form element.",
                    //        info: "This method has been called on element :\n" + outerHtml(this[0])
                    //    });
                    //    return this;
                    //}

                    var inputFieldSelector = "[" + vpGrid.HtmlDataTag.ColumnName + "]";
                    var jqInputFields = this.find(inputFieldSelector);

                    if (jqInputFields.notFound()) {
                        vpGrid.logError({
                            functionName: "updateRowFromThisForm",
                            message: "Cannot find input fields with selector : '" + inputFieldSelector + "'",
                            info: "Check that all input fields is tagged with the html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'"
                        });
                        return this;
                    }


                    var fieldsCount = jqInputFields.length;
                    var dataRow = {};
                    for (var i = 0; i < fieldsCount; i++) {
                        var element = jqInputFields[i];
                        var jqElement = $(element);
                        var colName = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnName, "");
                        if (colName.isNullOrEmptyOrWhitespace()) {
                            vpGrid.logError({
                                functionName: "updateRowFromThisForm",
                                message: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " is not correctly setup on element :\n" + outerHtml(element),
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " must be the name of a column"
                            });
                            continue;
                        }

                        if (JQGrid.colDoesNotExist(colName)) {
                            vpGrid.logError({
                                functionName: "updateRowFromThisForm",
                                message: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " is not correctly setup on element :\n" + outerHtml(element),
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " must be the name of an existing column."
                            });
                            continue;
                        }

                        var inputValue = jqElement.val();
                        //if input is a select, take only the displayed value
                        //TODO : create a keyValueFormatter to be able to handle the selected key directly
                        if (jqElement.is('select')) {
                            var jqSelectedOption = jqElement.find('option:selected');
                            inputValue = jqSelectedOption.text();
                        }

                        dataRow[colName] = inputValue;

                    }//end for (var i = 0; i < fieldsCount; i++) 

                    
                    vpGrid.updateRow(dataRow, params);
                    return this;

                } catch (e) {
                    vpGrid.logException(e);
                    return this;
                }

            }
        });








        $.fn.extend({
            validateThisForm: function () {
                /// <signature>
                /// <summary>Validate all fields in the current form element.</summary>
                /// <returns type="Object">Returns a literal object that contains the result of the validation process.
                ///                         this object has the following structure : 
                ///                         {
                ///                             isValid: true | false,
                ///                             <colName> : {isValid:true|false, message:"any error message"}
                ///
                ///</returns>
                /// </signature>
                try {
                    if (this === null) {
                        return null;
                    }

                    if (this === undefined) {
                        return null;
                    }

                    if (this.length === undefined) {
                        return null;
                    }

                    if (this.length === 0) {
                        return null;
                    }

                    //if (this.isNot('form')) {
                    //    vpGrid.logError({
                    //        functionName: "validateNewRow",
                    //        message: "This method should be called on a form element.",
                    //        info: "This method has been called on element :\n" + outerHtml(this[0])
                    //    });
                    //    return null;
                    //}

                    var inputFieldSelector = "[" + vpGrid.HtmlDataTag.ColumnName + "]";
                    var jqInputFields = this.find(inputFieldSelector);

                    if (jqInputFields.notFound()) {
                        vpGrid.logError({
                            functionName: "validateThisForm",
                            message: "Cannot find input fields with selector : '" + inputFieldSelector + "'",
                            info: "Check that all input fields is tagged with the html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'"
                        });
                        return null;
                    }


                    var fieldsCount = jqInputFields.length;
                    var validationResult = {
                        isValid : true
                    };
                    for (var i = 0; i < fieldsCount; i++) {
                        var element = jqInputFields[i];
                        var jqElement = $(element);
                        var colName = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnName, "");
                        if (colName.isNullOrEmptyOrWhitespace()) {
                            vpGrid.logError({
                                functionName: "validateThisForm",
                                message: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " is not correctly setup on element :\n" + outerHtml(element),
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " must be the name of a column"
                            });
                            continue;
                        }

                        if (JQGrid.colDoesNotExist(colName)) {
                            vpGrid.logError({
                                functionName: "validateThisForm",
                                message: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " is not correctly setup on element :\n" + outerHtml(element),
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " must be the name of an existing column."
                            });
                            validationResult.isValid = false;
                            validationResult[colName] = {
                                isValid: false,
                                message: 'there is an internal configuration error on this field. Check error log.'
                            };
                            continue;
                        }

                        validationResult[colName] = {
                            isValid: true,
                            message: ''
                        };

                        var inputValue = jqElement.val();
                        var jqGridTable = JQGrid.host();
                        var jqGridValidationResult = $.jgrid.checkValues.call(jqGridTable[0], inputValue, colName);
                        if (isNullOrUndefinedOrEmpty(jqGridValidationResult)) {
                            //TODO : log
                            continue;
                        }

                        if (jqGridValidationResult[0] === false) {
                            validationResult.isValid = false;
                            validationResult[colName] = {
                                isValid: false,
                                message: jqGridValidationResult[1]
                            };
                            continue;
                        }

                    }//end for (var i = 0; i < fieldsCount; i++) 


                    if (validationResult.isValid === true) {
                        //TODO : raise event to let listeners do a global custom validation on the form

                    }


                    return validationResult;

                } catch (e) {
                    vpGrid.logException(e);
                    return null;
                }

            }
        });

        $.fn.extend({
            showValidationErrorsOnThisForm: function (validationResult) {
                /// <signature>
                /// <summary>Show all validation error messages on this form.</summary>
                /// <param name="validationResult" type="Object">Literal object that contains validation errors. Look at validateThisForm jQuery extension to see the details of that object.</param>
                /// <returns type="void"></returns>
                /// </signature>
                try {
                    if (this === null) {
                        return this;
                    }

                    if (this === undefined) {
                        return this;
                    }

                    if (this.length === undefined) {
                        return this;
                    }

                    if (this.length === 0) {
                        return this;
                    }

                    if (isNullOrUndefinedOrEmpty(validationResult)) {
                        //TODO : reset all validation error messages
                    }

                    //if (this.isNot('form')) {
                    //    vpGrid.logError({
                    //        functionName: "showValidationErrorsOnThisForm",
                    //        message: "This method should be called on a form element.",
                    //        info: "This method has been called on element :\n" + outerHtml(this[0])
                    //    });
                    //    return this;
                    //}

                    var inputFieldSelector = "[" + vpGrid.HtmlDataTag.ColumnName + "]";
                    var jqInputFields = this.find(inputFieldSelector);

                    if (jqInputFields.notFound()) {
                        vpGrid.logError({
                            functionName: "showValidationErrorsOnThisForm",
                            message: "Cannot find input fields with selector : '" + inputFieldSelector + "'",
                            info: "Check that all input fields is tagged with the html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'"
                        });
                        return this;
                    }

                    var fieldsCount = jqInputFields.length;
                    var dataRow = {};
                    for (var i = 0; i < fieldsCount; i++) {
                        var element = jqInputFields[i];
                        var jqElement = $(element);
                        var colName = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnName, "");
                        if (colName.isNullOrEmptyOrWhitespace()) {
                            vpGrid.logError({
                                functionName: "showValidationErrorsOnThisForm",
                                message: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " is not correctly setup on element :\n" + outerHtml(element),
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " must be the name of a column"
                            });
                            continue;
                        }

                        if (JQGrid.colDoesNotExist(colName)) {
                            vpGrid.logError({
                                functionName: "showValidationErrorsOnThisForm",
                                message: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " is not correctly setup on element :\n" + outerHtml(element),
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnName + "'," + " must be the name of an existing column."
                            });
                            continue;
                        }

                        var jqInputDivContainer = jqElement.closest('div');
                        var jqErrorMessageDiv = jqInputDivContainer.find('div.ui-validation-message');

                        if (jqErrorMessageDiv.notFound()) {
                            jqErrorMessageDiv = $("<div></div>", {
                                'class' : 'ui-validation-message vp-grid-hidden'
                            });
                            jqErrorMessageDiv.insertAfter(jqElement);
                        }
      
                        var inputValidationResult = validationResult[colName];
                        if (isNullOrUndefinedOrEmpty(inputValidationResult)) {
                            jqErrorMessageDiv.html("");
                            jqErrorMessageDiv.addClass('vp-grid-hidden');

                            jqElement.removeClass('ui-state-error');

                            continue;
                        }

                        if (inputValidationResult.isValid) {
                            jqErrorMessageDiv.html("");
                            jqErrorMessageDiv.addClass('vp-grid-hidden');

                            jqElement.removeClass('ui-state-error');
                            //jqInputDivContainer.removeClass('height-auto');

                            continue;
                        }

                        jqErrorMessageDiv.html(inputValidationResult.message);
                        jqErrorMessageDiv.removeClass('vp-grid-hidden');
                        jqElement.addClass('ui-state-error');
                        jqInputDivContainer.addClass('height-auto');
                        
                    }//end for (var i = 0; i < fieldsCount; i++) 

                    return this;

                } catch (e) {
                    vpGrid.logException(e);
                    return this;
                }

            }
        });

        $.fn.extend({
            resetValidationErrors: function () {
                /// <signature>
                /// <summary>Remove all validation error messages on this form.</summary>
                /// <returns type="void"></returns>
                /// </signature>
                try {
                    if (this === null) {
                        return this;
                    }

                    if (this === undefined) {
                        return this;
                    }

                    if (this.length === undefined) {
                        return this;
                    }

                    if (this.length === 0) {
                        return this;
                    }

                    //if (this.isNot('form')) {
                    //    vpGrid.logError({
                    //        functionName: "resetValidationErrors",
                    //        message: "This method should be called on a form element.",
                    //        info: "This method has been called on element :\n" + outerHtml(this[0])
                    //    });
                    //    return this;
                    //}

                    var validationSelector = 'div.ui-validation-message';
                    var jqValidations = this.find(validationSelector);

                    jqValidations.html("").addClass('vp-grid-hidden');

                    var inputFieldSelector = "[" + vpGrid.HtmlDataTag.ColumnName + "]";
                    var jqInputFields = this.find(inputFieldSelector);

                    jqInputFields.removeClass('ui-state-error');

                    return this;

                } catch (e) {
                    vpGrid.logException(e);
                    return this;
                }

            }
        });

        $.fn.extend({
            setSelectedOptionWithText: function (inputText) {
                /// <signature>
                /// <summary>Set the selected option on a select element. The option is selected if its text matches input text.</summary>
                /// <param name="inputText" type="String">Option display text to search for on the selec element.</param>
                /// <returns type="void"></returns>
                /// </signature>
                try {
                    if (this === null) {
                        return this;
                    }

                    if (this === undefined) {
                        return this;
                    }

                    if (this.length === undefined) {
                        return this;
                    }

                    if (this.length === 0) {
                        return this;
                    }

                    if (! this.is('select')) {
                        vpGrid.logError({
                            message: "Dom element is not a SELECT : \n" + outerHtml(this[0]),
                            functionName: "setSelectedOptionWithText"
                            
                        });
                    }

                    var jqOptions = this.find('option');
                    if (jqOptions.notFound()) {
                        return this;
                    }

                    var optionsCount = jqOptions.length;
                    for (var i = 0; i < optionsCount; i++) {
                        var selectOption = jqOptions[i];
                        var jqSelectOption = $(selectOption);
                        if (jqSelectOption.text() === inputText) {
                            jqSelectOption.attr('selected', 'true');
                            break;
                        }
                    }

                    return this;

                } catch (e) {
                    vpGrid.logException(e);
                    return this;
                }

            }
        });


        // end jQuery extensions

        //private extensions
        function isEmpty(input) {
            try {

                if (input === undefined) {
                    return true;
                }

                if (input === null) {
                    return true;
                }

                if (input.length === 0) {
                    return true;
                }

                //check for native types
                if (typeof input === "number") {
                    return false;
                }

                //check for native types
                if (typeof input === "boolean") {
                    return false;
                }

                if (typeof input === "function") {
                    return false;
                }

                // check for empty literal object
                var propertyCount = 0;
                for (var i in input) {
                    propertyCount += 1;
                }
                if (propertyCount === 0) {
                    return true;
                }

                return false;

            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return false;
            }
        }

        function isNullOrUndefined(input) {
            try {
                if (input === undefined) {
                    return true;
                }

                if (input === null) {
                    return true;
                }

                return false;

            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return false;
            }
        }

        function isNullOrUndefinedOrEmpty(input) {
            try {
                if (isNullOrUndefined(input)) {
                    return true;
                }

                return isEmpty(input);

            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return false;
            }
        }

        function isNotNullOrUndefinedOrEmpty(input) {
            return isNullOrUndefinedOrEmpty(input) === false;
        }

        function isBoolean(input) {
            try {
                if (isNullOrUndefined(input)) {
                    return false;
                }

                if (typeof input === "boolean") {
                    return true;
                }

                return false;
            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        }

        function isNotBoolean(input) {
            return isBoolean(input) === false;
        }

        function isString(input) {
            try {
                if (isNullOrUndefined(input)) {
                    return false;
                }

                if (typeof input === "string") {
                    return true;
                }
                //hack from hdo
                if (typeof input.isString !== "function") {
                    return false;
                }

                if (input.isString()) {
                    return true;
                }

                return false;

            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        };

        function isNotString(input) {
            return isString(input) === false;
        };

        function isFunction(input) {
            try {
                if (isNullOrUndefined(input)) {
                    return false;
                }

                if (typeof input === "function") {
                    return true;
                }

                return false;
            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return false;
            }
        };

        function isNotFunction(input) {
            return isFunction(input) === false;
        };

        function isNumber(input) {
            try {
                if (isNullOrUndefined(input)) {
                    return false;
                }
                if (isNaN(input)) {
                    return false;
                }
                if (typeof input === "number") {
                    return true;
                }

                if (isNotString(input)) {
                    return false;
                }

                // at this step we know that input is a string
                // try to convert to float
                var numberValue = input.toFloat();
                if (isNaN(numberValue)) {
                    return false;
                }

                return true;

            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        };

        function isNotNumber(input) {
            return isNumber(input) === false;
        };

        function isInt(input) {
            try {
                if (isNullOrUndefined(input)) {
                    return false;
                }
                if (isNaN(input)) {
                    return false;
                }

                if (typeof input !== "number") {
                    return false;
                }

                var remainder = input % 1;
                if (remainder === 0) {
                    return true;
                }

                return false;

            } catch (e) {
                //TODO : log
                vpGrid.logException(e);
                return false;
            }
        };

        function isNotInt(input) {
            return isInt(input) === false;
        };

        function isArray(input) {
            try {
                if (isNullOrUndefined(input)) {
                    return false;
                }

                // TODO : jsHint suggests to refactor
                //if (typeof input === "array") {
                //    return true;
                //}

                if (input.push) {
                    return true;
                }

                return false;

            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        };

        function isNotArray(input) {
            return isArray(input) === false;
        };

        function outerHtml(element) {
            try {
                if (isNullOrUndefined(element)) {
                    return "";
                }

                if (element.outerHTML) {
                    return element.outerHTML;
                }



                return "";

            } catch (e) {
                vpGrid.logException(e);
                return "";
            }
        };

        function extendOrMerge(obj1, obj2) {
            /// <signature>
            /// <summary>Extend obj1 with obj2 properties.</summary>
            /// <param name="obj1" type="Object">a litteral object to be extended</param>
            /// <param name="obj2" type="Object">feeder object literal</param>
            /// <returns type="Object">Returns obj1 augmented with properties coming from obj2. If obj1 and obj2 have identical propertiy, this property is converted to an array in obj1, and obj2 property value is pushed in this array.</returns>
            /// </signature>
            try {
                if (isNullOrUndefinedOrEmpty(obj2)) {
                    return obj1;
                }

                if (isNullOrUndefined(obj1)) {
                    var newObj = {};
                    $.extend(newObj, obj2);
                    return newObj;
                }

                if (isEmpty(obj1)) {
                    $.extend(obj1, obj2);
                    return obj1;
                }

                for (var i in obj2) {
                    var propertyName = i;
                    // check if this property exists in obj1
                    if (obj1[propertyName]) {
                        convertPropertyToArray(obj1, propertyName);
                        obj1[propertyName].push(obj2[propertyName]);
                        delete obj2[propertyName];
                    }
                }

                $.extend(obj1, obj2);
                return obj1;

            } catch (e) {
                vpGrid.logException(e);
                return obj1;
            }

        };

        function convertPropertyToArray(input, propertyName) {
            try {

                if (isNullOrUndefinedOrEmpty(input)) {
                    return;
                }

                if (isNotString(propertyName)) {
                    return;
                }

                if (isNullOrUndefined(input[propertyName])) {
                    return;
                }

                // now we are sure that the property named propertyName exists on input object
                var obj = input[propertyName];
                if (isArray(obj)) {
                    // the conversion is already done
                    return input;
                }

                input[propertyName] = [];
                input[propertyName].push(obj);

                return input;

            } catch (e) {
                vpGrid.logException(e);
                return;
            }
        };

        function tryFindFunctionByName(input) {
            try {
                if (isNullOrUndefinedOrEmpty(input)) {
                    return null;
                }

                if (isNotString(input)) {
                    return null;
                }

                // check if the function exist in the root object
                var foundFunction = window[input];
                if (isFunction(foundFunction)) {
                    return foundFunction;
                }

                // function is defined in a namespace
                var namespaces = input.split(".");
                if (isNullOrUndefinedOrEmpty(namespaces)) {
                    return null;
                }

                var functionName = namespaces[namespaces.length - 1];
                var parentObject = window;
                for (var i = 0; i < namespaces.length - 1; i++) {
                    var namespace = namespaces[i];
                    parentObject = parentObject[namespace];
                }

                foundFunction = parentObject[functionName];
                if (isFunction(foundFunction)) {
                    return foundFunction;
                }

                vpGrid.logError({
                    functionName: "tryFindFunctionByName",
                    message: "Cannot find function named : '" + input + "'"
                });
                return null;

            } catch (e) {
                vpGrid.logException(e);
                return null;
            }
        };

        var asyncKeys = {};
        function executeAsync(context, f, delay, asyncKey) {
            try {
                if (isNullOrUndefined(context)) {
                    context = this;
                }

                if (isNotFunction(f)) {
                    vpGrid.logError({
                        functionName: "executeAsync",
                        message: "Input handler is not a function : '" + f + "'"
                    });
                    return;
                }

                var defaultDelay = 0;
                if (isNumber(delay)) {
                    defaultDelay = delay;
                }



                if (isNullOrUndefinedOrEmpty(asyncKey)) {
                    //setTimeout(f, defaultDelay);

                    setTimeout(function () {
                        f.call(context);
                    }, defaultDelay);

                    return;
                }

                //debounce
                if (asyncKeys[asyncKey]) {
                    clearTimeout(asyncKeys[asyncKey]);
                }
                asyncKeys[asyncKey] = setTimeout(function () {
                    f.call(context);
                }, defaultDelay);


            } catch (e) {
                vpGrid.logException(e);
                setTimeout(f, 0);
            }
        };

        function isCustomPropertyOf(input, property) {
            /// <signature>
            /// <summary>Check if a property is a custom property of input literal object. You should use this method only with literal objects.</summary>
            /// <param name="input" type="Object">Literal object on which the property is searched</param>
            /// <param name="property" type="Object">The property to search on input literal object.</param>
            /// <returns type="Boolean">Returns true if the property is a custom property inside input literal object.</returns>
            /// </signature>
            try {

                if (input === null) {
                    return false;
                }

                if (input === undefined) {
                    return false;
                }

                if (!input.hasOwnProperty) {
                    return false;
                }

                if (input.hasOwnProperty(property)) {
                    return true;
                }

                return false;

            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        };

        function isNotCustomPropertyOf(input, property) {
            return isCustomPropertyOf(input, property) === false;
        };

        function areEquals(input1, input2) {
            /// <signature>
            /// <summary>Check if a literal object input1  is equal to input2 literal object. You should compare only literal objects. </summary>
            /// <param name="input1" type="Object">Literal object</param>
            /// <param name="input2" type="Object">Literal object to be compared with input1</param>
            /// <returns type="Boolean">Returns true if input1 has same properties and values as input2 literal object.</returns>
            /// </signature>
            try {
                if (input1 === null) {
                    return false;
                }

                if (input1 === undefined) {
                    return false;
                }

                if (input2 === null) {
                    return false;
                }

                if (input2 === undefined) {
                    return false;
                }

                for (var p in input1) {
                    if (isNotCustomPropertyOf(input2, p)) {
                        return false;
                    }
                    if (input1[p] !== input2[p]) {
                        return false;
                    }
                }

                return true;

            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        };

        function isInRange(input, minValue, maxValue) {
            /// <signature>
            /// <summary>Check if input value is between minValue and maxValue</summary>
            /// <param name="input" type="Number">Input value</param>
            /// <param name="minValue" type="Number">Minimum value of the interval</param>
            /// <param name="maxValue" type="Number">Max value of the interval</param>
            /// <returns type="Boolean">Returns true if input is in the interval.</returns>
            /// </signature>
            try {

                if (minValue === null && maxValue === null) {
                    return true;
                }

                if (isNotNumber(input)) {
                    return false;
                }

                if (isString(input)) {
                    input = input.toFloat();
                }

                if (input.isGreaterThan(maxValue)) {
                    return false;
                }

                if (input.isLowerThan(minValue)) {
                    return false;
                }

                return true;

            } catch (e) {
                vpGrid.logException(e);
                return false;
            }
        };

        function isOutOfRange(input, minValue, maxValue) {
            /// <signature>
            /// <summary>Check if input value is not in the interval [minValue,maxValue]</summary>
            /// <param name="input" type="Number">Input value</param>
            /// <param name="minValue" type="Number">Minimum value of the interval</param>
            /// <param name="maxValue" type="Number">Max value of the interval</param>
            /// <returns type="Boolean">Returns true if input is not in the interval.</returns>
            /// </signature>
            return isInRange(input, minValue, maxValue) === false;
        };

        //end private extensions

        // jQuery-UI extensions
        function bindWidgetOnElement(element) {
            try {
                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                // take the name of the widget from the data tag
                var widgetType = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.UIWidget, "");

                //deserialize the configuration options object from the data tag
                var dataTag = vpGrid.HtmlDataTag.UIWidgetOptions.removePrefix("data-");
                var widgetOptions = jqElement.data(dataTag);

                if (widgetType === "datepicker") {
                    // bind datepicker widget
                    //merge widget Options with vpGrid datepicker Options
                    var mergedOptions = $.extend({}, vpGridOptions.datepickerOptions, widgetOptions);

                    jqElement.datepicker(mergedOptions);
                    return;
                } // end if

                if (widgetType === "button") {
                    // bind button widget
                    jqElement.button(widgetOptions);
                    return;
                } // end if

                if (widgetType === "dialog") {
                    // bind dialog widget
                    // bind internal event handler onDialogClosed
                    //TODO : check if an handler is already bound
                    var source = element;
                    widgetOptions.close = function (event, ui) {
                        try {
                            var eventArgs = {};
                            // raise event so that listeners can do extra process
                            onModalDialogClosed(source, eventArgs);

                        } catch (e) {
                            vpGrid.logException(e);
                        }
                    };

                    jqElement.dialog(widgetOptions);
                    return;
                } // end if

                if (widgetType === "autocomplete") {
                    //bind autocomplete widget
                    bindAutoCompleteWidgetOnElement(element);
                    return;
                } // end if

                if (widgetType === "accordion") {
                    //bind accordion widget
                    jqElement.accordion(widgetOptions);
                    return;
                } // end if

                if (widgetType === "tabs") {
                    //bind tabs widget
                    jqElement.tabs(widgetOptions);
                    return;
                } // end if

                if (widgetType === "fileupload") {
                    //bind File Upload widget (http://blueimp.github.io/jQuery-File-Upload/)
                    bindFileUploadWidgetOnElement(element);
                    return;
                } // end if


                vpGrid.logError({
                    functionName: "bindWidgetOnElement",
                    message: "widget binding is not implemented for widget : '" + widgetType + "'  in vpGrid.",
                    info: "This widget is not binded on element : \n" + outerHtml(element)
                });

            } catch (e) {
                vpGrid.logException(e);
            }
        };




        function bindFileUploadWidgetOnElement(element) {
            /// <signature>
            /// <summary>Bind the Jquery plgin File Upload from http://blueimp.github.io/jQuery-File-Upload/ </summary>
            /// <param name="element" type="Object">DOM object on which to bind the jquery plugin</param>
            /// <returns type="Void"></returns>
            /// </signature>
            try {
                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                //deserialize the configuration options object from the data tag
                var dataTag = vpGrid.HtmlDataTag.UIWidgetOptions.removePrefix("data-");
                var widgetOptions = jqElement.data(dataTag);

                jqElement.fileupload(widgetOptions);

                //bind events
                $('#fileupload').bind('fileuploadsubmit', function (e, data) {
                    try {
                        var formData = data.formData || {};
                        var source = e.target;

                        var eventArgs = {
                            data : data,
                            formData: formData,
                            cancel : false
                        };

                        //raise event to enable listeners inspect/modify the formData or cancel the ajax submit call
                        onFileuploading(source, eventArgs);

                        if (isNotNullOrUndefinedOrEmpty(eventArgs.formData)) {
                            data.formData = eventArgs.formData;
                        }

                        if (eventArgs.cancel === true) {
                            return false;
                        }

                        return true;

                    } catch (e) {
                        vpGrid.logException(e);
                        // enable submit even if an error has occured
                        return true;
                    }

                });
                

            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function bindAutoCompleteWidgetOnElement(element) {
            try {

                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                var widgetDataSource = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DataSource, "")
                var widgetDataSourceType = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DataSourceType, vpGrid.HtmlDataTag.DefaultValue.DataSourceType);

                if (widgetDataSource.isNullOrEmptyOrWhitespace()) {
                    //TODO : log
                    vpGrid.logError({
                        message: "data attribute : " + vpGrid.HtmlDataTag.DataSource + " is not defined on element \n: " + outerHtml(element)
                    });
                    return;
                }

                if (widgetDataSourceType === "web") {
                    bindAutoCompleteWidgetFromWebOnElement(element, widgetDataSource);
                    return;
                }

                //TODO : log
                vpGrid.logError({
                    functionName: "bindAutoCompleteWidgetOnElement",
                    message: "data attribute : " + vpGrid.HtmlDataTag.DataSourceType + " on element \n: " + outerHtml(element) + "\n has a value that is not implemented in vpGrid."
                });

            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function bindAutoCompleteWidgetFromWebOnElement(element, dataSourceUrl) {
            try {
                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                var ajaxOptions = {
                    cache: false,
                    type: "GET",
                    url: dataSourceUrl,
                    dataType: "json",
                    element: element,
                    success: function (response) {
                        bindAutoCompleteWidgetFromWebResponseOnElement(response, element);
                    }

                }

                $.extend(ajaxOptions, vpGridAjaxOptions);

                //TODO : raise event to enable listerners inspect and/or modify ajaxOptions

                $.ajax(ajaxOptions);


            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function bindAutoCompleteWidgetFromWebResponseOnElement(response, element) {
            try {

                //TODO : raise event to enable listerners inspect and/or modify response
                if (isNullOrUndefinedOrEmpty(response)) {
                    //TODO : log
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                if (response.done === undefined) {
                    //TODO : log
                    return;
                }

                if (response.done === false) {
                    var details = "Ajax Request error on fetching data for autocomplete";
                    logServerError(response, details, element);
                    return;
                }

                var data = response.data;
                bindAutoCompleteWidgetWithDataOnElement(element, data);

            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function bindAutoCompleteWidgetWithDataOnElement(element, data) {
            try {

                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                //deserialize the configuration options object from the data tag
                var dataTag = vpGrid.HtmlDataTag.UIWidgetOptions.removePrefix("data-");
                var widgetOptions = jqElement.data(dataTag);
                if (isNullOrUndefined(widgetOptions)) {
                    widgetOptions = {};
                }

                widgetOptions.source = data;

                // set default minLength value if not already setup
                if (isNullOrUndefinedOrEmpty(widgetOptions.minLength)) {
                    widgetOptions.minLength = 0;
                }

                jqElement.autocomplete(widgetOptions);
                jqElement.bind('focus', function () {
                    try {
                        var jqCurrent = $(this);
                        executeAsync(this, function () {
                            try {
                                var currentValue = jqCurrent.val();
                                if (isNullOrUndefinedOrEmpty(currentValue)) {
                                    currentValue = "";
                                }

                                jqCurrent.autocomplete("search", currentValue);

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                });

                jqElement.bind('click', function () {
                    try {
                        var jqCurrent = $(this);
                        executeAsync(this, function () {
                            try {
                                jqCurrent.autocomplete("search", "");

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                });


            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function destroyWidgetOnElement(element) {
            try {
                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                if (jqElement.datepicker) {
                    //unbind the close event
                    jqElement.datepicker("option", "onClose", function () { });
                    jqElement.datepicker('hide');
                    jqElement.datepicker("destroy");
                    return;
                }

                if (jqElement.autocomplete) {
                    jqElement.autocomplete("close");
                    jqElement.autocomplete("destroy");
                    return;
                }

                vpGrid.logError({
                    functionName: "destroyWidgetOnElement",
                    message: "Widget destroy is not implemented on element : " + outerHtml(element)
                });

                //TODO : implement destroy of other possible widgets

            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function hideWidgetOnElement(element) {
            try {
                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                if (jqElement.datepicker) {
                    jqElement.datepicker('hide');
                    return;
                }

                if (jqElement.autocomplete) {
                    jqElement.autocomplete("close");
                    return;
                }

                vpGrid.logError({
                    message: "Widget hide is not implemented on element : \n" + outerHtml(element)
                });

                //TODO : implement hide of other possible widgets

            } catch (e) {
                vpGrid.logException(e);
            }
        };

        // end jQuery-UI extensions


        //UI extensions
        function applyDisabledStateOnElement(element) {
            try {
                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                jqElement.attr('disabled', true).addClass("ui-state-disabled");


            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function applyActiveHeaderOnElement(element) {
            try {
                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                jqElement.mouseenter(
                   function () {
                       $(this).find('[role=vp-grid-passive-header]').addClass('vp-grid-hidden');
                       $(this).find('[role=vp-grid-active-header]').removeClass('vp-grid-hidden');
                       $(this).saveOriginalClassAttributeContent();
                       $(this).addClass($(this).attr(vpGrid.HtmlDataTag.CssToAdd));
                       //bind event handlers
                       bindHandlersOnElement(this);
                   }
                   );

                jqElement.mouseleave(
                    function () {
                        $(this).find('[role=vp-grid-passive-header]').removeClass('vp-grid-hidden');
                        $(this).find('[role=vp-grid-active-header]').addClass('vp-grid-hidden');
                        $(this).restoreOriginalClassAttributeContent();


                    }
                    );

            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function bindDataSourceOnElement(element) {
            try {
                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                if (jqElement.is("select")) {
                    //bind data source on select
                    bindDataSourceOnSelectElement(element);
                    return;
                } // end if

            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function bindDataSourceOnSelectElement(element) {
            try {

                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                var selectDataSource = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DataSource, "")
                var selectDataSourceType = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DataSourceType, vpGrid.HtmlDataTag.DefaultValue.DataSourceType);

                if (selectDataSource.isNullOrEmptyOrWhitespace()) {
                    //TODO : log
                    vpGrid.logError({
                        message: "data attribute : " + vpGrid.HtmlDataTag.DataSource + " is not defined on element : \n" + outerHtml(element)
                    });
                    return;
                }

                if (selectDataSourceType === "web") {
                    bindDataSourceFromWebOnSelectElement(element, selectDataSource);
                    return;
                }

                //TODO : log
                vpGrid.logError({
                    message: "data attribute : " + vpGrid.HtmlDataTag.DataSourceType + " on element : \n" + outerHtml(element) + "\n has a value that is not implemented in vpGrid."
                });



            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function bindDataSourceFromWebOnSelectElement(element, dataSourceUrl) {
            try {
                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                var ajaxOptions = {
                    cache: false,
                    type: "GET",
                    url: dataSourceUrl,
                    dataType: "json",
                    element: element,
                    success: function (response) {
                        bindDataSourceFromWebResponseOnSelectElement(response, element);
                    }

                }

                $.extend(ajaxOptions, vpGridAjaxOptions);

                //TODO : raise event to enable listerners inspect and/or modify ajaxOptions

                $.ajax(ajaxOptions);


            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function bindDataSourceFromWebResponseOnSelectElement(response, element) {
            try {

                //TODO : raise event to enable listerners inspect and/or modify response
                if (isNullOrUndefinedOrEmpty(response)) {
                    //TODO : log
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                if (response.done === undefined) {
                    //TODO : log
                    return;
                }

                if (response.done === false) {
                    var details = "Ajax Request error on fetching data for select element";
                    logServerError(response, details, element);
                    return;
                }

                var data = response.data;
                bindSelectWithDataOnElement(element, data);

            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function bindSelectWithDataOnElement(element, data) {
            try {

                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                //TODO : check that data param is an array
                //TODO ; check that items in the array are of the form { key:xx, value:yy [,selected: true]}

                //keep track of the currently selected item
                var jqSelectedOptionBefore = jqElement.find('option:selected');
                var selectedValueBefore = jqSelectedOptionBefore.val();

                //empty the select element
                jqElement.find('option').remove();

                var length = data.length;

                for (var i = 0; i < length; i++) {
                    var item = data[i];

                    var optionValue = item.key;
                    var optionText = item.value;
                    var isSelected = false;
                    if (item.selected) {
                        isSelected = true;
                    }

                    var optionElement = $("<option></option>").attr("value", optionValue).text(optionText);
                    if (isSelected) {
                        optionElement.attr("selected", "true");
                    }
                    jqElement.append(optionElement);

                }

                //Check if the selected item has changed
                //keep track of the currently selected item
                var jqSelectedOptionAfter = jqElement.find('option:selected');
                var selectedValueAfter = jqSelectedOptionAfter.val();

                if (selectedValueBefore !== selectedValueAfter) {
                    //raise the Change event
                    jqElement.change();
                }


            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function fillContentPlaceholderOnElement(element) {
            try {
                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                var dataSource = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DataSource, "")
                var dataSourceType = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DataSourceType, vpGrid.HtmlDataTag.DefaultValue.DataSourceType);

                if (dataSource.isNullOrEmptyOrWhitespace()) {
                    //TODO : log
                    vpGrid.logError({
                        message: "data attribute : " + vpGrid.HtmlDataTag.DataSource + " is not defined on element : \n" + outerHtml(element)
                    });
                    return;
                }

                if (dataSourceType === "handler") {
                    fillContentPlaceholderFromHandlerOnElement(element, dataSource);
                    return;
                }

                //TODO : log
                vpGrid.logError({
                    message: "data attribute : " + vpGrid.HtmlDataTag.DataSourceType + " on element : \n" + outerHtml(element) + "\n has a value that is not implemented in vpGrid."
                });
            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function fillContentPlaceholderFromHandlerOnElement(element, handlerName) {
            try {
                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                var handler = tryFindFunctionByName(handlerName)

                if (isNotFunction(handler)) {
                    var domHTML = outerHtml(element);
                    vpGrid.logError({
                        functionName: "fillContentPlaceholderFromHandlerOnElement",
                        message: "Cannot find handler named : '" + handlerName + "' defined on element: \n" + domHTML
                    });
                    return;
                }

                // call handler to get html content
                var newContent = handler();
                if (isNullOrUndefinedOrEmpty(newContent)) {
                    newContent = "";
                }

                jqElement.html(newContent);

            } catch (e) {
                vpGrid.logException(e);
            }
        };

        // end UI extensions

        //UI event handlers auto binding
        function bindHandlersOnElement(element) {
            try {
                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                // check if handlers have already been registered 
                var handlersRegistered = jqElement.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.HandlersRegistered, false);
                if (handlersRegistered) {
                    return;
                }

                //deserialize the configuration options object from the data tag
                var dataTag = vpGrid.HtmlDataTag.Handlers.removePrefix("data-");
                var handlers = jqElement.data(dataTag);


                //handlers is a literal object that is like :
                // {"click" : { "handler" : "MyCompany.MyHandler", "async" : true, "asyncKey" : "myHandlerKey"}}

                if (isNullOrUndefinedOrEmpty(handlers)) {
                    //TODO : log
                    return;
                }

                for (var i in handlers) {
                    var eventName = i;
                    var handlerOptions = handlers[i];
                    bindHandlerOnElement(element, eventName, handlerOptions);
                }

                // flag that events have been binded
                jqElement.attr(vpGrid.HtmlDataTag.HandlersRegistered, "true");


            } catch (e) {
                vpGrid.logException(e);
            }
            finally {

            }
        };

        function bindHandlerOnElement(element, eventName, handlerOptions) {
            try {
                if (isNullOrUndefined(element)) {
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    return;
                }

                if (isNullOrUndefinedOrEmpty(eventName)) {
                    //TODO : log
                    return;
                }

                if (isNotString(eventName)) {
                    //TODO : log

                    return;
                }

                if (isNullOrUndefinedOrEmpty(handlerOptions)) {
                    //TODO : log
                    return;
                }

                var handlerName = handlerOptions.handler;
                var handler = tryFindFunctionByName(handlerName)

                if (isNotFunction(handler)) {
                    var domHTML = outerHtml(element);
                    vpGrid.logError({
                        message: "Cannot find handler named : '" + handlerName + "' for " + eventName + " event defined on element: \n" + domHTML
                    });
                    return;
                }

                if (isNullOrUndefined(handlerOptions.async)) {
                    handlerOptions.async = false;
                }

                if (eventName === "click" && handlerOptions.async === false) {
                    jqElement.click(handler);
                    //TODO : take handlerOptions.params
                    return;
                }

                if (eventName === "change" && handlerOptions.async === false) {
                    jqElement.change(handler);
                    return;
                }

                if (eventName === "click" && handlerOptions.async === true) {
                    jqElement.click(function (event) {
                        //TODO : get asyncKey from data attribute
                        //TODO : get prevent default behavior from data attribute

                        if (event) {
                            if (event.preventDefault) {
                                event.preventDefault();
                            }

                        }
                        var context = this;
                        var params = handlerOptions.params;
                        executeAsync(this, function () {
                            //propagate the context up to the event handler
                            handler.call(this, event,params);
                        });
                    });


                    return;
                }

                if (eventName === "change" && handlerOptions.async === true) {
                    jqElement.change(function (event) {
                        //TODO : get asyncKey from data attribute
                        //TODO : get prevent default behavior from data attribute

                        if (event) {
                            if (event.preventDefault) {
                                event.preventDefault();
                            }
                        }

                        var context = this;
                        var params = handlerOptions.params;

                        executeAsync(this, function () {
                            //propagate the context up to the event handler
                            handler.call(context, event,params);
                        });
                    });


                    return;
                }

                //TODO : log error event handler not implemented

            } catch (e) {
                vpGrid.logException(e);
            }
            finally {

            }
        };
        //end UI event handlers auto binding


        //vpGrid Events
        //Public Events enumeration
        vpGrid.Event = vpGrid.Event || {};
        vpGrid.Event.onSecurityTrimming = "onSecurityTrimming";
        vpGrid.Event.onTimelineCreated = "onTimelineCreated";
        vpGrid.Event.onBehaviorsRegistering = "onBehaviorsRegistering";
        vpGrid.Event.onBehaviorsRegistered = "onBehaviorsRegistered";
        vpGrid.Event.onTimelineExecuting = "onTimelineExecuting";


        vpGrid.Event.onDataReceived = "onDataReceived";
        //This event is raised when the response data has been received from remote server.
        //this event enables to change the received data before loading it in the grid.
        //for example the server might sent "compressed data" or "unreadable" data to optimize security and bandwidth
        //this event enables listener to transform a non readable received data into a meaningfull data.
        //Listeners might also add or remove any data to or from the received data.
        //Event handler must have the following signature : function(source, eventArgs)
        //the eventArgs parameter has the following signature : 
        //      eventArgs = {
        //        data: [{col1:xxx, col2:yyy, ... colN:zzz}, ...]
        //      };
        // The data property of the eventArgs object is an array of objects. Each object in the array represent a row in the grid. 
        // The property names of these objects must be the name of an existing column in the grid.

        
        vpGrid.Event.onCellRendering = "onCellRendering";
        //This event is raised when a cell is rendering and jqGrid is about to render the <td> cell container.
        //this event enables to setup the html attributes of the <td> cell container. 
        //You cannot set the <td> html content with this event.
        //Event handler must have the following signature : function(source, eventArgs)
        //the eventArgs parameter has the following signature : 
        //      eventArgs = {
        //        cellName: cellname,
        //        cellValue: value,
        //        rowData: data,
        //        td : {}
        //      };
        // The event handler can set the eventArgs.td literal object with properties corresponding to html attributes.
        // for example : eventArgs.td.title = 'xxx', eventArgs.td.class = 'myclass', eventArgs.td.style="xxx'


        
        vpGrid.Event.onSummaryCellRendering = "onSummaryCellRendering";
        //This event is raised when a summary cell is rendering.
        //this event enables to setup the value of the summary cell and also the html attributes of the <td> cell container.
        //Event handler must have the following signature : function(source, eventArgs)
        //the eventArgs parameter has the following signature : 
        //      eventArgs = {
        //        cellName: cellname,
        //        cellValue: value,
        //        useCellFormatter : false,
        //        uiIdentifier : xxxx  -> value of the data tag data-vp-grid-ui-id
        //        td : {},
        //        remove :{}
        //      };
        // The event handler can set the eventArgs.td literal object with properties corresponding to html attributes.
        // The uiIdentifier property enables listener to know on which summary row he is called:
        //          if there is only one summary row (this is the default): uiIdentifier=""
        //          if there are more than one summary row: uiIdentifier = "SumarryRowN" where N = 1,2,3, ...
        // If existing attributes or classes must be removed, the event handler should fill the remove property.
        // For example, to remove the ui-state-error class on the td : remove.class='ui-state-error'.
        // for example : eventArgs.td.title = 'xxx', eventArgs.td.class = 'myclass', eventArgs.td.style="xxx'
        // The Event handler should also setup the cellValue property. This value will be rendered in the cell summary.
        // If cellValue must be rendered in the same format as other cells in the column, the event handler should explicitely set the useCellFormatter property to true.


        
        vpGrid.Event.onSelectCellRendering = "onSelectCellRendering";
        //This event is raised when a cell is in edit mode and needs to be rendered as a select statement <select>...</select>
        //Event handler must have the following signature : function(source, eventArgs)
        //the eventArgs parameter has the following signature : 
        //      eventArgs = {
        //        cellName: cellname,
        //        cellValueBeforeEditing: value,
        //        rowData: data,
        //        selectOptions : []
        //      };
        // The event handler should fill the eventArgs.selectOptions with literal objects of type : { key : xxx, value : yyy} (a collection of key/value pairs)
        // if there is no listener or if listener(s) does nothing, the selectOptions array will be be automatically filled with all distinct values of the column.


        
        vpGrid.Event.onAutocompleteCellRendering = "onAutocompleteCellRendering";
        //This event is raised when a cell is in edit mode and needs to be rendered as an input statement <input>...</input> with autocomplete bound to it.
        //Event handler must have the following signature : function(source, eventArgs)
        //the eventArgs parameter has the following signature : 
        //      eventArgs = {
        //        cellName: cellname,
        //        cellValue: value,
        //        options : {},  -> options parameter of autocomplete jquery-ui
        //        data: [],
        //      };
        // The event handler should fill the data array with strings. This array will be bound to autocomplete.
        // if there is no listener or if listener(s) does nothing, the data array will be be automatically filled with all distinct values of the column.


        
        vpGrid.Event.onImageCellRendering = "onImageCellRendering";
        //This event is raised when a cell is in display mode and needs to be rendered as an image statement <img>...</img>


        
        vpGrid.Event.onLinkCellRendering = "onLinkCellRendering";
        //This event is raised when a cell is in display mode and needs to be rendered as a link statement <a>...</a>


        
        vpGrid.Event.onCellValidating = "onCellValidating";
        //This event is raised when a cell is in edit mode and needs to be validated through custom validation
        //Event handler must have the following signature : function(source, eventArgs)
        //the eventArgs parameter has the following signature : 
        //      eventArgs = {
        //        cellName: cellname,
        //        cellValue: value, -> cellValue is always a string
        //        cellNativeValue : cellValue converted to the column schema data type (only works for numbers at the moement)
        //        rowData: data,
        //        isValid : true,
        //        errorMessage : 'xxx'
        //      };
        // The event handler should set the eventArgs.isValid property to false and the eventArgs.errorMessage property if custom validation fails.


        
        vpGrid.Event.onCellUpdating = "onCellUpdating";
        // This Event is raised when a cell is in edit mode and the underlying data is about to be updated.


         
        vpGrid.Event.onCellUpdated = "onCellUpdated";
        //This event is raised when a cell has been updated after its content has been edited
        //Event handler must have the following signature : function(source, eventArgs)
        //the eventArgs parameter has the following signature : 
        //      eventArgs = {
        //        cellName: cellname,
        //        cellValue: value,
        //        rowid: id, 
        //        rowData: data
        //      };
        // The event handler uses eventArgs properties to make any additional processing on the grid. 
        // For example: 
        //      - changing other cells of the same row by applying specific business rules.
        //          -> to change another cell, the event listener may set the rowData.colName property of the corresponding cell
        //      - updating the summary row


        vpGrid.Event.onRowInserted = "onRowInserted";
        //This event is raised when a row has been inserted in the grid. 
        // This event is raised when data is loaded from server and when data has been filtered/sorted in the grid.
        //Event handler must have the following signature : function(source, eventArgs)
        //the eventArgs parameter has the following signature : 
        //      eventArgs = {
        //        rowid: id, 
        //        rowData: data
        //      };
        // The event handler uses eventArgs properties to make any additional processing on the grid. 
        // For example: 
        //      - changing other cells of the same row by applying specific business rules.
        //          -> to change another cell, the event listener may set the rowData.colName property of the corresponding cell
        //      - adding/updating inline summary rows




        vpGrid.Event.onInlineSummaryRowRendering = "onInlineSummaryRowRendering";
        //This event is raised when a row has been inserted in the grid. 
        // This event is raised when data is loaded from server, when data has been filtered/sorted in the grid.
        // This event enable listeners to insert/update inline summary rows for the target row
        //Event handler must have the following signature : function(source, eventArgs)
        //the eventArgs parameter has the following signature : 
        //      eventArgs = {
        //        rowid: id, 
        //        rowData: data
        //      };
        // The event handler uses eventArgs properties as input data to create or update an inline summary row.
        // inline summary rows are created/updated using the public methods : 
        //                                              vpGrid.insertInlineSummaryRowAfter,
        //                                              vpGrid.updateInlineSummaryRowAfter
        






        vpGrid.Event.onModalDialogClosing = "onModalDialogClosing";


        vpGrid.Event.onModalDialogClosed = "onModalDialogClosed";
        //Event raised when a modal dialog is closed. 
        //Event listener must have the signature function(source, eventArgs){}


        vpGrid.Event.onFileuploading = "onFileuploading";
        //This event is raised when a file is about to be uploaded
        //Event handler must have the following signature : function(source, eventArgs)
        //the eventArgs parameter has the following signature : 
        //      eventArgs = {
        //          data : data, -> data object built by the jquery File Upload plugin
        //          formData: formData, -> literal Object that will be added in the POST Request
        //          cancel : false
        //      };
        // The event handler can prevent the file to be uploaded by setting the cancel property to true.
        // The event handler may send any additional data (key/value) to the server by extending the formData object.
        // The event handler must not modify the data eventArgs.data object : modfying it is at your own risk.


        //End Public Events enumeration


        //Private Events Enumeration
        var PrivateEvent = {};
        PrivateEvent.onBehaviorsRegistering = "private.onBehaviorsRegistering";

        //EventHandlers layer
        var EventHandlers = (function () {
            var eventHandlers = {};
            try {
                var listeners = {};
                //private methods on EventHandlers layer
                function eventHasListeners(eventName) {
                    try {
                        if (isNotString(eventName)) {
                            return false;
                        }

                        if (eventName.isNullOrEmptyOrWhitespace()) {
                            return false;
                        }

                        if (isNullOrUndefinedOrEmpty(listeners)) {
                            return false;
                        }

                        var eventNameListeners = listeners[eventName];

                        if (isNullOrUndefinedOrEmpty(eventNameListeners)) {
                            return false;
                        }

                        return true;

                    } catch (e) {
                        //TODO : log
                        vpGrid.logException(e);
                        return false;
                    }
                }

                function eventHasNoListener(eventName) {
                    return eventHasListeners(eventName) === false;
                }

                function eventHandlerIsRegistered(eventName, handler) {
                    try {
                        if (eventHasNoListener(eventName)) {
                            return false;
                        }

                        if (isNullOrUndefined(handler)) {
                            return false;
                        }

                        if (isNotFunction(handler)) {
                            return false;
                        }

                        // get all listeners for this event
                        var eventListeners = listeners[eventName];
                        var listernersCount = eventListeners.length;

                        for (var i = 0; i < listernersCount; i++) {
                            if (eventListeners[i] === handler) {
                                return true;
                            }
                        }

                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                }

                //public methods on this layer
                eventHandlers.registerEventHandler = function (eventName, handler) {
                    /// <signature>
                    /// <summary>Register your event handler to one of the vpGrid events</summary>
                    /// <param name="eventName" type="String">Name of the event you want to listen to. Possible names are defined in the the vpGrid enumeration vpGrid.Event</param>
                    /// <param name="handler" type="Function">Function that will be called when raising the event. This function must have the signature function(source, eventArgs){}, where source is the object that is at the origin of the event, and eventArgs is a placeholder object for informations needed by the listener.</param>
                    /// </signature>
                    try {
                        if (isNotFunction(handler)) {
                            //TODO : log
                            return;
                        }

                        // check if event handler has already been registered
                        if (eventHandlerIsRegistered(eventName, handler)) {
                            return;
                        }
                        var eventListeners = listeners[eventName];
                        if (isNullOrUndefinedOrEmpty(eventListeners)) {
                            listeners[eventName] = [];
                        }

                        listeners[eventName].push(handler);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                eventHandlers.raiseEvent = function (eventName, eventSource, eventArgs) {
                    try {
                        if (eventHasNoListener(eventName)) {
                            return;
                        }

                        var eventListeners = listeners[eventName];
                        var listernersCount = eventListeners.length;

                        for (var i = 0; i < listernersCount; i++) {
                            handler = eventListeners[i];
                            try {
                                // execute handler
                                handler(eventSource, eventArgs);

                                //TODO : check if cancel has been setup in eventArgs
                            } catch (e) {
                                //TODO : log
                                vpGrid.logException(e);
                            }
                        }

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }


            } catch (e) {
                //error in  EventHandlers layer
                vpGrid.logException(e);
            }
            finally {
                return eventHandlers;
            }

        })();
        //end EventHandlers layer
        // public interface on Event Handlers
        vpGrid.registerEventHandler = function (eventName, handler) {
            try {
                EventHandlers.registerEventHandler(eventName, handler);
            } catch (e) {
                vpGrid.logException(e);
            }

        };

        function onFileuploading(source,eventArgs) {
            try {
                // make a backup copy of eventArgs
                var eventArgsCopy = $.extend({}, eventArgs);

                EventHandlers.raiseEvent(vpGrid.Event.onFileuploading, source, eventArgs);

                // check possible misbehavior from listeners
                if (isNullOrUndefinedOrEmpty(eventArgs)) {
                    vpGrid.logError({
                        functionName: "onFileuploading",
                        message: "eventArgs object corrupted by listener",
                        info: "eventArgs object is reverted to its original state"
                    });
                    $.extend(eventArgs, eventArgsCopy);
                    return;
                }

                if (isNullOrUndefinedOrEmpty(eventArgs.formData)) {
                    eventArgs.formData = eventArgsCopy.formData;
                }


            } catch (e) {
                vpGrid.logException(e);
            }
        }
        // end public interface on Event Handlers



        //Behaviors layer
        var Behaviors = (function () {
            var behaviors = {};
            try {
                // Sequence Enumeration
                behaviors.Sequence = {};
                behaviors.Sequence.SequenceInit = "SequenceInit";
                behaviors.Sequence.GridPreInit = "GridPreInit";
                behaviors.Sequence.GridInit = "GridInit";
                behaviors.Sequence.GridLoading = "GridLoading";
                behaviors.Sequence.GridLoaded = "GridLoaded";
                behaviors.Sequence.SequenceEnd = "SequenceEnd";
                behaviors.Sequence.SequenceUndefined = "SequenceUndefined";

                var defaultTimeline = [
                    behaviors.Sequence.SequenceInit,
                    behaviors.Sequence.GridPreInit,
                    behaviors.Sequence.GridInit,
                    behaviors.Sequence.GridLoading,
                    behaviors.Sequence.GridLoaded,
                    behaviors.Sequence.SequenceEnd
                ];

                function createTimeline() {
                    try {
                        // create a copy of the default timeline array
                        var timeline = defaultTimeline.slice(0);

                        return timeline;

                    } catch (e) {
                        vpGrid.logException(e);
                        return [];
                    }

                }

                //registered behaviors
                var timelineBehaviors = {};

                //private methods on Behaviors layer
                function timelineSequenceHasBehaviors(sequenceName) {
                    try {
                        if (isNotString(sequenceName)) {
                            return false;
                        }

                        if (sequenceName.isNullOrEmptyOrWhitespace()) {
                            return false;
                        }

                        if (isNullOrUndefinedOrEmpty(timelineBehaviors)) {
                            return false;
                        }

                        var sequenceNameBehaviors = timelineBehaviors[sequenceName];

                        if (isNullOrUndefinedOrEmpty(sequenceNameBehaviors)) {
                            return false;
                        }

                        return true;

                    } catch (e) {
                        //TODO : log
                        vpGrid.logException(e);
                        return false;
                    }
                }

                function timelineSequenceHasNoBehavior(sequenceName) {
                    return timelineSequenceHasBehaviors(sequenceName) === false;
                }

                function behaviorIsRegistered(sequenceName, handlerInfo) {
                    try {
                        if (timelineSequenceHasNoBehavior(sequenceName)) {
                            return false;
                        }

                        if (isNullOrUndefinedOrEmpty(handlerInfo)) {
                            return false;
                        }

                        if (isNotFunction(handlerInfo.execute)) {
                            //TODO : log
                            return false;
                        }

                        // get all behaviors for this sequence
                        var sequenceNameBehaviors = timelineBehaviors[sequenceName];
                        var behaviorsCount = sequenceNameBehaviors.length;

                        for (var i = 0; i < behaviorsCount; i++) {
                            if (sequenceNameBehaviors[i].execute === handlerInfo.execute) {
                                return true;
                            }
                        }

                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                }

                function registerBehavior(sequenceName, handlerInfo) {
                    /// <signature>
                    /// <summary>Register a behavior to be executed when executing the timeline sequence</summary>
                    /// <param name="sequenceName" type="String">the name of a sequence inside the execution timeline.</param>
                    /// <param name="handlerInfo" type="Object">A literal object of form {execute: function, isAsync : boolean}. 
                    ///     execute property is the function that will be called (the behavior) when executing the timeline's sequence. 
                    ///     isAsync property signals if the behavior executes itself asynchronous.
                    /// </param>
                    /// </signature>
                    try {
                        if (isNotString(sequenceName)) {
                            vpGrid.logError({
                                message: "Cannot register behavior : the sequence name is not a string"
                            });
                            return;
                        }
                        if (isNullOrUndefinedOrEmpty(handlerInfo)) {
                            vpGrid.logError({
                                message: "Cannot register behavior on sequence : '" + sequenceName + "'. Behavior Info is null or empty."
                            });
                            return;
                        }

                        if (isNotFunction(handlerInfo.execute)) {
                            vpGrid.logError({
                                message: "Cannot register behavior : behavior callback is not a function."
                            });
                            return;
                        }

                        // check if behavior has already been registered
                        if (behaviorIsRegistered(sequenceName, handlerInfo)) {
                            return;
                        }

                        //set isAsync property if not set
                        if (isNotBoolean(handlerInfo.isAsync)) {
                            handlerInfo.isAsync = false;
                        }

                        var sequenceNameBehaviors = timelineBehaviors[sequenceName];
                        // check first time registration
                        if (isNullOrUndefinedOrEmpty(sequenceNameBehaviors)) {
                            timelineBehaviors[sequenceName] = [];
                        }

                        timelineBehaviors[sequenceName].push(handlerInfo);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function onTimelineCreated(eventArgs) {
                    try {

                        EventHandlers.raiseEvent(vpGrid.Event.onTimelineCreated, vpGrid, eventArgs);

                        //TODO : check eventArgs corruption
                        if (isNullOrUndefinedOrEmpty(eventArgs)) {
                            vpGrid.logError({
                                functionName: "onTimelineCreated",
                                message: "eventArgs object corrupted by listener"
                            });
                            return;

                        }

                        if (isNullOrUndefinedOrEmpty(eventArgs.timeline)) {
                            vpGrid.logError({
                                functionName: "onTimelineCreated",
                                message: "eventArgs.timeline object corrupted by listener"
                            });
                            return;

                        }

                        //TODO : check that timeline is an array and contains only strings





                    } catch (e) {
                        vpGrid.logException(e);
                    }

                }

                function onBehaviorsRegistration(timeline, eventName) {
                    try {
                        if (isNullOrUndefinedOrEmpty(timeline)) {
                            //TODO : log
                            return;
                        }
                        if (isNotString(eventName)) {
                            //TODO : log
                            return;
                        }

                        var timelineCount = timeline.length;
                        for (var i = 0; i < timelineCount; i++) {
                            var _sequenceName = timeline[i];
                            var eventArgs = {
                                sequenceName: _sequenceName,
                                behaviors: []
                            };
                            EventHandlers.raiseEvent(eventName, vpGrid, eventArgs);

                            if (isNullOrUndefinedOrEmpty(eventArgs.behaviors)) {
                                // no listeners or listeners that do nothing
                                continue;
                            }

                            // register behaviors given by listeners
                            var behaviorsCount = eventArgs.behaviors.length;
                            for (var j = 0; j < behaviorsCount; j++) {
                                registerBehavior(_sequenceName, eventArgs.behaviors[j]);
                            }
                        }

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function createExecutionSteps(timeline) {
                    try {
                        var steps = [];
                        if (isNullOrUndefinedOrEmpty(timeline)) {
                            vpGrid.logError({
                                functionName: "createExecutionSteps",
                                message: "timeline is empty : none of the behaviors will execute."
                            });
                            return;
                        }

                        var timelineCount = timeline.length;
                        for (var i = 0; i < timelineCount; i++) {
                            var _sequenceName = timeline[i];

                            // get behaviors registers for this sequence name
                            if (timelineSequenceHasNoBehavior(_sequenceName)) {
                                continue;
                            }
                            var _behaviors = timelineBehaviors[_sequenceName];
                            var behaviorsCount = _behaviors.length;
                            for (var j = 0; j < behaviorsCount; j++) {
                                var executionStep = {
                                    sequenceName: _sequenceName,
                                    behavior: _behaviors[j] // this property is a literal object like {isAsync : true|false, execute : function}
                                };
                                steps.push(executionStep);
                            } // end for

                        } // for (var i = 0; i < timelineCount; i++)

                        return steps;

                    } catch (e) {
                        vpGrid.logException(e);
                        return [];
                    }
                }

                function onTimelineExecuting(eventArgs) {
                    try {

                        //enable listeners to inspect and/or modify all execution steps
                        EventHandlers.raiseEvent(vpGrid.Event.onTimelineExecuting, vpGrid, eventArgs);

                        //TODO : check any corruption in eventArgs
                        //TODO : check any change in executionSteps

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function executeBehaviors(executionSteps) {
                    try {
                        if (isNullOrUndefinedOrEmpty(executionSteps)) {
                            //TODO : log
                            return;
                        }

                        function processNext() {
                            /// <signature>
                            /// <summary>Core execution engine of the timeline.
                            /// This engine is called multiple times until there is no behavior to execute
                            ///</summary>
                            /// </signature>
                            if (isNullOrUndefinedOrEmpty(executionSteps)) {
                                // there is no more step to execute
                                return;
                            }

                            var executionStep = executionSteps.shift();
                            //TODO : log execution step
                            // execute behavior
                            try {
                                // call the behavior and give him the callback method to call when its async processing is finished.
                                executionStep.behavior.execute(executionStep.sequenceName, processNext);
                                if (executionStep.behavior.isAsync) {
                                    // processNext will be called by the behavior itself
                                    return;
                                }

                                // let the UI update itself if needed
                                setTimeout(processNext, 0);

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        } // end function processNext()

                        //start execution engine
                        processNext();

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                //public methods on this layer
                //behaviors.registerBehavior = registerBehavior;

                behaviors.timelineSequenceExists = function (sequenceName) {
                    try {
                        if (isNotString(sequenceName)) {
                            return false;
                        }

                        if (sequenceName.isInArray(behaviors.currentTimeline)) {
                            return true;
                        }

                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                }

                behaviors.timelineSequenceDoesNotExist = function (sequenceName) {
                    return behaviors.timelineSequenceExists(sequenceName) === false;
                }

                behaviors.getTimelineSequenceOnElement = function (element, defaultTimelineSequence, behaviorName) {
                    try {
                        var jqElement = $(element);

                        if (jqElement.notFound()) {
                            //TODO : log
                            return behaviors.Sequence.SequenceUndefined;
                        }

                        if (isNotString(behaviorName)) {
                            behaviorName = "undefined behavior";
                        }

                        if (isNotString(defaultTimelineSequence)) {
                            defaultTimelineSequence = behaviors.Sequence.GridInit;
                        }

                        var dataSequenceName = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.TimelineSequence, "");
                        if (dataSequenceName.isNullOrEmptyOrWhitespace()) {
                            //TODO : log warning instead of error
                            vpGrid.logError({
                                message: "data attribute : " + vpGrid.HtmlDataTag.TimelineSequence + " is not defined on element : \n" + outerHtml(element),
                                info: "the following default value is applied to this data attribute: " + defaultTimelineSequence
                            });
                            dataSequenceName = defaultTimelineSequence;
                        }

                        if (behaviors.timelineSequenceDoesNotExist(dataSequenceName)) {
                            vpGrid.logError({
                                message: "data attribute value : " + vpGrid.HtmlDataTag.TimelineSequence + "='" + dataSequenceName + "' is not defined in the timeline. Target element : \n" + outerHtml(element),
                                info: "This value must be in [" + behaviors.currentTimeline.toString() + "]. Behavior " + behaviorName + " is not applied to this element."
                            });
                        }

                        return dataSequenceName;

                    } catch (e) {
                        vpGrid.logException(e);
                        return behaviors.Sequence.SequenceUndefined;
                    }
                }

                behaviors.executeTimeline = function () {
                    try {
                        var timeline = createTimeline();

                        //raise event to enable listeners to inspect and/or modify the timeline
                        var eventArgs = {
                            timeline: timeline
                        };
                        onTimelineCreated(eventArgs);

                        //make this timeline public
                        behaviors.currentTimeline = eventArgs.timeline;

                        //raise event onBehaviorsRegistering -> extension point to inject behaviors before internal behaviors
                        onBehaviorsRegistration(eventArgs.timeline, vpGrid.Event.onBehaviorsRegistering);

                        //inject internal behaviors
                        onBehaviorsRegistration(eventArgs.timeline, PrivateEvent.onBehaviorsRegistering);

                        //raise event onBehaviorsRegistered -> extension point to inject behaviors after internal behaviors
                        onBehaviorsRegistration(eventArgs.timeline, vpGrid.Event.onBehaviorsRegistered);

                        // get all execution steps
                        // an execution step is a behavior that will be executed at a specific point in the timeline
                        var executionSteps = createExecutionSteps(eventArgs.timeline);

                        //raise event onTimelineExecuting -> extension point to examine all execution steps in the timeline before they start executing
                        var eventArgs2 = {
                            executionSteps: executionSteps
                        };
                        onTimelineExecuting(eventArgs2);
                        executionSteps = eventArgs2.executionSteps;

                        //execute behaviors
                        executeBehaviors(executionSteps);

                    } catch (e) {
                        //TODO : log
                        vpGrid.logException(e);
                    }
                }

            } catch (e) {
                //error in  Behaviors layer
                vpGrid.logException(e);
            }
            finally {
                return behaviors;
            }
        })();
        //end Behaviors layer

        //internal behaviors definitions
        Behaviors.securityTrimmingBehavior = function (sequenceName) {
            /// <signature>
            /// <summary>This behavior implements security trimming within the vp-grid-container. Security trimming is a way to hide UI elements when user is not in a defined role.</summary>
            /// <param name="sequenceName" type="String">Name of a sequence that is currently executed by the timeline.</param>
            /// </signature>
            try {
                var jqContainer = vpGrid.currentContainer();
                if (jqContainer.notFound()) {
                    return;
                }

                if (isNotString(sequenceName)) {
                    vpGrid.logError({
                        message: "input sequenceName is not a string. SecurityTrimmingBehavior is aborted."
                    });
                    return;
                }

                //step 1 : find all UI elements that must be security trimmed in the sequence
                var selector = "[" + vpGrid.HtmlDataTag.securityTrimmed + "=true]";
                var jqElements = jqContainer.find(selector);
                if (jqElements.notFound()) {
                    return;
                }

                //step 2 : apply security trimming on each found elements
                var elementsCount = jqElements.length;
                for (var i = 0; i < elementsCount; i++) {
                    var element = jqElements[i];
                    var jqElement = $(element);

                    // check if security trimming must be applied on input sequenceName
                    var dataSequenceName = Behaviors.getTimelineSequenceOnElement(element, Behaviors.Sequence.GridPreInit, "securityTrimmingBehavior")

                    if (dataSequenceName !== sequenceName) {
                        continue;
                    }

                    //step 3 : by default hide this UI element
                    jqElement.hideEx();

                    //step 4 : raise event so that listeners can decide to trim or not to trim the element
                    var eventArgs = {
                        userIsInRole: false
                    };
                    var dataRoles = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.securityTrimmedRoles, "");
                    if (dataRoles.isNullOrEmptyOrWhitespace()) {
                        vpGrid.logError({
                            message: "data attribute : " + vpGrid.HtmlDataTag.securityTrimmedRoles + " is not defined on element : \n" + outerHtml(element)
                        });
                        dataRoles = "";
                    }

                    var roles = dataRoles.toArray(",");
                    eventArgs.roles = roles;

                    // ask listeners if user is in role
                    onSecurityTrimming(element, eventArgs);

                    //check if the userIsInRole has been setup
                    if (isNullOrUndefinedOrEmpty(eventArgs)) {
                        vpGrid.logError({
                            functionName: "securityTrimmingBehavior",
                            message: "eventArgs object corrupted by listener"
                        });
                        continue;
                    }

                    if (isNotBoolean(eventArgs.userIsInRole)) {
                        vpGrid.logError({
                            functionName: "securityTrimmingBehavior",
                            message: "eventArgs.userIsInRole boolean property corrupted by listener"
                        });
                        continue;
                    }

                    if (eventArgs.userIsInRole) {
                        // user is in role : element must be shown to user
                        jqElement.showEx();
                    }

                } // end for


            } catch (e) {
                vpGrid.logException(e);
            }

        }; //end Behaviors.securityTrimmingBehavior

        function onSecurityTrimming(element, eventArgs) {
            try {

                EventHandlers.raiseEvent(vpGrid.Event.onSecurityTrimming, element, eventArgs);

            } catch (e) {
                vpGrid.logException(e);
            }
        };

        Behaviors.DisableElementBehavior = function (sequenceName) {
            /// <signature>
            /// <summary>This behavior disables any UI element that is configured to be disabled within the vp-grid-container.</summary>
            /// <param name="sequenceName" type="String">Name of a sequence that is currently executed by the timeline.</param>
            /// </signature>
            try {
                var jqContainer = vpGrid.currentContainer();
                if (jqContainer.notFound()) {
                    //TODO : log info
                    return;
                }

                //step 1 : get all elements tagged with ui-disabled
                var elementsSelector = "[" + vpGrid.HtmlDataTag.UIDisabled + "=true]";
                var jqElements = $(elementsSelector);
                if (jqElements.notFound()) {
                    //TODO : log info
                    return;
                }

                // step 2 : take only elements that must be processed in this specific timeline sequence
                var elementsCount = jqElements.length;
                for (var i = 0; i < elementsCount; i++) {
                    var element = jqElements[i];
                    var jqElement = $(element);

                    var dataSequenceName = Behaviors.getTimelineSequenceOnElement(element, Behaviors.Sequence.GridLoading, "DataSourceBindingsBehavior")

                    if (dataSequenceName !== sequenceName) {
                        continue;
                    }

                    applyDisabledStateOnElement(element);

                } // end for (var i = 0; i < elementsCount; i++)


            } catch (e) {
                vpGrid.logException(e);
            }

        }; //end Behaviors.DisableElementBehavior

        Behaviors.ActiveHeaderBehavior = function (sequenceName) {
            /// <signature>
            /// <summary>This behavior implements active header within the vp-grid-container.
            /// Active header is a column header that toggles itself to a button on hoovering.
            ///</summary>
            /// <param name="sequenceName" type="String">Name of a sequence that is currently executed by the timeline.</param>
            /// </signature>
            try {
                var jqContainer = vpGrid.currentContainer();
                if (jqContainer.notFound()) {
                    //TODO : log info
                    return;
                }

                //step 1 : get all elements tagged with ui-element
                var elementsSelector = "[role=" + vpGrid.HtmlRoleAttribute.ActiveHeader + "][" + vpGrid.HtmlDataTag.UIElement + "=true]";
                var jqElements = $(elementsSelector);
                if (jqElements.notFound()) {
                    //TODO : log info
                    return;
                }

                // step 2 : take only elements that must be processed in this specific timeline sequence
                var elementsCount = jqElements.length;
                for (var i = 0; i < elementsCount; i++) {
                    var element = jqElements[i];
                    var jqElement = $(element);

                    var dataSequenceName = Behaviors.getTimelineSequenceOnElement(element, Behaviors.Sequence.GridLoading, "DataSourceBindingsBehavior")

                    if (dataSequenceName !== sequenceName) {
                        continue;
                    }

                    applyActiveHeaderOnElement(element);

                } // end for (var i = 0; i < elementsCount; i++)


            } catch (e) {
                vpGrid.logException(e);
            }

        }; //end Behaviors.ActiveHeaderBehavior

        Behaviors.DataSourceBindingsBehavior = function (sequenceName) {
            /// <signature>
            /// <summary>This behavior implements data source binding within the vp-grid-container.</summary>
            /// <param name="sequenceName" type="String">Name of a sequence that is currently executed by the timeline.</param>
            /// </signature>
            try {
                var jqContainer = vpGrid.currentContainer();
                if (jqContainer.notFound()) {
                    //TODO : log info
                    return;
                }

                //step 1 : get all elements tagged with ui-element
                var elementsSelector = "[" + vpGrid.HtmlDataTag.UIElement + "=true]";
                var jqElements = $(elementsSelector);
                if (jqElements.notFound()) {
                    //TODO : log info
                    return;
                }

                // step 2 : take only elements that must be processed in this specific timeline sequence
                var elementsCount = jqElements.length;
                for (var i = 0; i < elementsCount; i++) {
                    var element = jqElements[i];
                    var jqElement = $(element);

                    var dataSequenceName = Behaviors.getTimelineSequenceOnElement(element, Behaviors.Sequence.GridLoading, "DataSourceBindingsBehavior")

                    if (dataSequenceName !== sequenceName) {
                        continue;
                    }


                    //check if ui element must bind to a data source
                    var dataSource = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DataSource, "");

                    if (dataSource.isNotNullOrEmptyOrWhitespace()) {
                        bindDataSourceOnElement(element);
                    }

                } // end for (var i = 0; i < elementsCount; i++)


            } catch (e) {
                vpGrid.logException(e);
            }

        }; //end Behaviors.DataSourceBindingsBehavior

        Behaviors.UIWidgetsBehavior = function (sequenceName) {
            /// <signature>
            /// <summary>This behavior implements jQuery-ui widgets binding within the vp-grid-container.</summary>
            /// <param name="sequenceName" type="String">Name of a sequence that is currently executed by the timeline.</param>
            /// </signature>
            try {
                var jqContainer = vpGrid.currentContainer();
                if (jqContainer.notFound()) {
                    return;
                }

                //step 1 : get all elements tagged with ui-widget
                var elementsSelector = "[" + vpGrid.HtmlDataTag.UIWidget + "]";
                var jqElements = $(elementsSelector);
                if (jqElements.notFound()) {
                    //TODO : log info
                    return;
                }

                // step 2 : take only elements that must be processed in this specific timeline sequence
                var elementsCount = jqElements.length;
                for (var i = 0; i < elementsCount; i++) {
                    var element = jqElements[i];
                    var jqElement = $(element);

                    var dataSequenceName = Behaviors.getTimelineSequenceOnElement(element, Behaviors.Sequence.GridLoading, "UIWidgetsBehavior")

                    if (dataSequenceName !== sequenceName) {
                        continue;
                    }

                    bindWidgetOnElement(element);
                }


            } catch (e) {
                vpGrid.logException(e);
            }

        }; //end Behaviors.UIWidgetsBehavior

        Behaviors.BindHandlersBehavior = function (sequenceName) {
            /// <signature>
            /// <summary>This behavior implements event handlers binding within the vp-grid-container.</summary>
            /// <param name="sequenceName" type="String">Name of a sequence that is currently executed by the timeline.</param>
            /// </signature>
            try {
                var jqContainer = vpGrid.currentContainer();
                if (jqContainer.notFound()) {
                    //TODO : log
                    return;
                }

                //step 1 : get all elements tagged with data-vp-grid-handlers
                var elementsSelector = "[" + vpGrid.HtmlDataTag.Handlers + "]";
                var jqElements = $(elementsSelector);
                if (jqElements.notFound()) {
                    //TODO : log info
                    return;
                }

                // step 2 : take only elements that must be processed in this specific timeline sequence
                var elementsCount = jqElements.length;
                for (var i = 0; i < elementsCount; i++) {
                    var element = jqElements[i];
                    var jqElement = $(element);

                    var dataSequenceName = Behaviors.getTimelineSequenceOnElement(element, Behaviors.Sequence.GridLoading, "BindHandlersBehavior")

                    if (dataSequenceName !== sequenceName) {
                        continue;
                    }

                    bindHandlersOnElement(element);
                }


            } catch (e) {
                vpGrid.logException(e);
            }

        }; //end Behaviors.BindHandlersBehavior

        Behaviors.FillContentPlaceholderBehavior = function (sequenceName) {
            /// <signature>
            /// <summary>This behavior implements content injection within the vp-grid-container.</summary>
            /// <param name="sequenceName" type="String">Name of a sequence that is currently executed by the timeline.</param>
            /// </signature>
            try {
                var jqContainer = vpGrid.currentContainer();
                if (jqContainer.notFound()) {
                    //TODO : log
                    return;
                }

                //step 1 : get all elements tagged with data-vp-grid-ui-content-placeholder
                var elementsSelector = "[" + vpGrid.HtmlDataTag.UIContentPlaceholder + "=true]";
                var jqElements = $(elementsSelector);
                if (jqElements.notFound()) {
                    //TODO : log info
                    return;
                }

                // step 2 : take only elements that must be processed in this specific timeline sequence
                var elementsCount = jqElements.length;
                for (var i = 0; i < elementsCount; i++) {
                    var element = jqElements[i];
                    var jqElement = $(element);

                    var dataSequenceName = Behaviors.getTimelineSequenceOnElement(element, Behaviors.Sequence.GridLoaded, "FillContentPlaceholderBehavior")

                    if (dataSequenceName !== sequenceName) {
                        continue;
                    }

                    fillContentPlaceholderOnElement(element);
                }


            } catch (e) {
                vpGrid.logException(e);
            }

        }; //end Behaviors.BindHandlersBehavior

        Behaviors.GridInitBehavior = function (sequenceName, timelineExecutionCallback) {
            /// <signature>
            /// <summary>This behavior implements jqGrid configuration and instanciation</summary>
            /// <param name="sequenceName" type="String">Name of a sequence that is currently executed by the timeline.</param>
            /// <param name="sequenceName" type="Function">Core timeline execution engine to be called when execution of this behavior is async</param>
            /// </signature>
            try {
                JQGrid.init();

            } catch (e) {
                vpGrid.logException(e);
            }

        };

        Behaviors.GridLoadBehavior = function (sequenceName, timelineExecutionCallback) {
            /// <signature>
            /// <summary>This behavior implements jqGrid data loading</summary>
            /// <param name="sequenceName" type="String">Name of a sequence that is currently executed by the timeline.</param>
            /// <param name="sequenceName" type="Function">Core timeline execution engine to be called back when execution of this behavior is async</param>
            /// </signature>
            try {
                JQGrid.loadData(timelineExecutionCallback);

            } catch (e) {
                vpGrid.logException(e);
            }

        };

        Behaviors.GridLoadedBehavior = function (sequenceName, timelineExecutionCallback) {
            /// <signature>
            /// <summary>This behavior implements jqGrid configuration after data is loaded</summary>
            /// <param name="sequenceName" type="String">Name of a sequence that is currently executed by the timeline.</param>
            /// <param name="sequenceName" type="Function">Core timeline execution engine to be called back when execution of this behavior is async</param>
            /// </signature>
            try {
                JQGrid.bindAutocompleteOnSearchInputs();

            } catch (e) {
                vpGrid.logException(e);
            }

        };

        //end internal behaviors definitions

        //private Eventhandlers
        var PrivateEventHandlers = {};
        PrivateEventHandlers.injectInternalBehaviors = function (source, eventArgs) {
            try {
                if (isNullOrUndefined(eventArgs)) {
                    //TODO : log
                    return;
                }

                var _sequenceName = eventArgs.sequenceName;
                if (isNotString(_sequenceName)) {
                    //TODO : log
                    return;
                }

                //register securityTrimming behavior at all steps
                eventArgs.behaviors.push(
                    {
                        execute: Behaviors.securityTrimmingBehavior,
                        isAsync: false
                    });

                //register UIElements behavior at all steps
                eventArgs.behaviors.push(
                        {
                            execute: Behaviors.DataSourceBindingsBehavior,
                            isAsync: false
                        });

                eventArgs.behaviors.push(
                        {
                            execute: Behaviors.ActiveHeaderBehavior,
                            isAsync: false
                        });

                //register UIWidgets behavior at all steps
                eventArgs.behaviors.push(
                        {
                            execute: Behaviors.UIWidgetsBehavior,
                            isAsync: false
                        });

                //register BindHandlers behavior at all steps
                eventArgs.behaviors.push(
                        {
                            execute: Behaviors.BindHandlersBehavior,
                            isAsync: false
                        });

                //register DisableElement behavior at all steps
                eventArgs.behaviors.push(
                        {
                            execute: Behaviors.DisableElementBehavior,
                            isAsync: false
                        });

                if (_sequenceName === Behaviors.Sequence.GridInit) {
                    eventArgs.behaviors.push(
                        {
                            execute: Behaviors.GridInitBehavior,
                            isAsync: false
                        });

                }

                if (_sequenceName === Behaviors.Sequence.GridLoading) {
                    eventArgs.behaviors.push(
                        {
                            execute: Behaviors.GridLoadBehavior,
                            isAsync: true
                        });
                }

                if (_sequenceName === Behaviors.Sequence.GridLoaded) {
                    eventArgs.behaviors.push(
                        {
                            execute: Behaviors.GridLoadedBehavior,
                            isAsync: false
                        });
                }


            } catch (e) {
                vpGrid.logException(e);
            }
        };

        function registerPrivateHandlers() {
            try {

                vpGrid.registerEventHandler(PrivateEvent.onBehaviorsRegistering, PrivateEventHandlers.injectInternalBehaviors)

            } catch (e) {
                vpGrid.logException(e);
            }

        };

        function onModalDialogClosed(element, eventArgs) {
            try {
                if (isNullOrUndefinedOrEmpty(element)) {
                    vpGrid.logError({
                        functionName: "onModalDialogClosed",
                        message: "input element is null or empty or undefined",
                        info: "listeners to this event are not called"
                    });
                    return;
                }

                var jqElement = $(element);
                if (jqElement.notFound()) {
                    vpGrid.logError({
                        functionName: "onModalDialogClosed",
                        message: "Input element not found \n: " + outerHtml(element)
                    });
                    return;
                }

                if (isNullOrUndefined(eventArgs)) {
                    eventArgs = {};
                }

                var dialogId = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DialogId, "");
                if (dialogId.isNullOrEmptyOrWhitespace()) {
                    vpGrid.logError({
                        functionName: "onModalDialogClosed",
                        message: "data attribute : " + vpGrid.HtmlDataTag.DialogId + " is not defined on element \n: " + outerHtml(element)
                    });
                }

                eventArgs.dialogId = dialogId;

                EventHandlers.raiseEvent(vpGrid.Event.onModalDialogClosed, element, eventArgs);

            } catch (e) {
                vpGrid.logException(e);
            }
        };


        // end vpGrid Events

        // jqGrid layer
        var JQGrid = (function (vpGridOptions) {
            var jqGrid = {};
            try {
                jqGrid.options = {
                    datatype: "local",
                    //height: 275,    // 12 rows
                    height: 390,    // 17 rows
                    //height: 181,    // 8 rows
                    //width: 500,
                    autowidth: true,
                    shrinkToFit: true,
                    ignoreCase: true,
                    altRows: false,
                    loadonce: true, //all data is loaded locally
                    rowNum: 10,
                    caption: '',
                    multiselect: true,
                    multiboxonly: true,
                    hidegrid: false,
                    cellEdit: true,
                    cellsubmit: 'clientArray',
                    gridview: true,
                    viewrecords: false,
                    toolbar: [true, "bottom"], // bottom toolbar is used as a status bar only
                    headertitles: true,
                    footerrow: false,
                    hoverrows: false,
                    direction: "ltr",

                    // add-on for vpGrid
                    rowHeight: 23,  // one row in jqGrid is 23 pixels height
                    minColWidth: 60,
                    toprow: false, // summary row below jqGrid headers
                    numberOfSummaryRows: 1,
                    autoInsertNewLineAtBottom: true
                };

                jqGrid.Id = "vpGridExcel";
                jqGrid.remoteOperationPending = false;

                // total number of items loaded in the grid from remote server
                // this filed is updated by jqGrid.loadDataFromWebResponse function
                jqGrid.totalItemCount = 0;

                // total number of items seen in the grid by filtering through the search filter toolbar
                // this field is update by jqGrid.rows function
                jqGrid.filteredItemCount = 0;

                jqGrid.hasFrozenColumns = false;
                jqGrid.hasLockedColumns = false;

                jqGrid.currentRowId = null;

                jqGrid.options.beforeSelectRow = function (rowid, e) {
                    try {
                        //update current selected row
                        jqGrid.currentRowId = rowid;

                        var target = e.target;
                        var cellSelector = "td[role=gridcell]";
                        var jqElement = $(target).closest(cellSelector);
                        var isSummaryRow = false;

                        if (jqElement.notFound()) {
                            // check for summary row
                            var cellSelector2 = "td[role=summarygridcell]";
                            jqElement = $(target).closest(cellSelector2);
                            isSummaryRow = true;
                        }

                        if (jqElement.found() && (isSummaryRow === true)) {
                            //TODO : log
                            //prevent cell editing
                            return false;
                        }

                        if (jqElement.notFound()) {
                            vpGrid.logError({
                                message: "Selector not found : '" + cellSelector + "'",
                                functionName: "jqGrid.options.beforeSelectRow",
                                info: "Check that '" + cellSelector + "'" + " is parent of element :\n" + outerHtml(target)

                            });
                            return true; // allow row selection
                        }
                        //extract colName
                        var tagValue = jqElement.toStringOrDefaultFromAttribute("aria-describedby","");
                        var colName = tagValue.removePrefix(jqGrid.Id + '_');
                        var colModel = jqGrid.colModelOf(colName);

                        if (colModel.isDeleteAction) {
                            jqElement.click(function (event) {
                                try {
                                    if (event) {
                                        if (event.preventDefault) {
                                            event.preventDefault();
                                        }
                                        if (event.stopPropagation) {
                                            event.stopPropagation()
                                        }
                                    }
                                    if (jqGrid.canDeleteRowWithId(rowid)) {
                                        showDeleteItemMessage(rowid);
                                        return;
                                    }

                                    showCannotDeleteItemMessage(rowid);
                                    

                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                            });
                            //fire the event
                            executeAsync(jqElement[0], function () {
                                jqElement.click();
                                });
                        }

                        return true; // allow row selection

                    } catch (e) {
                        vpGrid.logException(e);
                        return true; // allow row selection
                    }

                }

                jqGrid.options.beforeRenderingCell = function (rowid, value, rawObject, colModel, rowData) {
                    /// <signature>
                    /// <summary>jqGrid extension (from vpGrid) to let listeners inject custom attributes (style/title/class/...) on the td cell element that jqGrid is about to render.</summary>
                    /// <param name="rowid" type="String">The id of the row</param>
                    /// <param name="value" type="String">Value of the cell being rendered by jqGrid</param>
                    /// <param name="rawObject" type="Object">????</param>
                    /// <param name="colModel" type="Object">Column model of the cell</param>
                    /// <param name="rowData" type="Object">Literal object containing column values. Each property is the name of the corresponding column (as set in the column model).</param>
                    /// <returns type="String">Returns all attributes serialized as one string.</returns>
                    /// </signature>
                    try {

                        var data = rowData;
                        var cellName = colModel.name;

                        if ( cellName.isNotCustomPropertyOf(rowData)) {
                            vpGrid.logError({
                                functionName: "jqGrid.options.beforeRenderingCell",
                                message: "Cannot find property named : '" + cellName + "' within input object rowData. rowid : '" + rowid + "'"
                            });
                        }
                        var cellValue = rowData[cellName];

                        var eventArgs = {
                            cellName: cellName,
                            cellValue: cellValue, //do not take value input parameter because it is a formatted value
                            rowData: data,
                            td: {}
                        };

                        //raise event to enable listeners set attributes on the <td> element
                        onCellRendering(eventArgs);

                        //TODO : if listeners have done nothing : augment eventArgs when min and max value is set on colModel and current Value is out of range
                        if (jqGrid.cellValueIsOutOfRange(rowid,cellName,cellValue,colModel)) {
                            if (isNullOrUndefinedOrEmpty(eventArgs.td['class'])) {
                                eventArgs.td['class'] = "";
                            }
                            eventArgs.td['class'] += " ui-state-error";
                        }
                        
                        var htmlAttributes = "";
                        if (isString(eventArgs.td.title)) {
                            htmlAttributes += (' title="' + eventArgs.td.title.toEncodedHTML() + '"');
                        }

                        if (isString(eventArgs.td['class'])) {
                            htmlAttributes += (' class="' + eventArgs.td['class'] + '"');
                        }

                        if (isString(eventArgs.td.style)) {
                            htmlAttributes += (' style="' + eventArgs.td.style + '"');
                        }

                        //TODO : check if listeners have injected other html attributes

                        return htmlAttributes;


                    } catch (e) {
                        vpGrid.logException(e);
                        return "";
                    }

                }

                jqGrid.options.beforeEditCell = function (rowid, cellname, value, iRow, iCol) {
                    try {
                        //update current selected row
                        jqGrid.currentRowId = rowid;

                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                message: "ColModels not found : beforeEditCell is stopped. rowid='" + rowid + "'" + "; cellName='" + cellname + "'"
                            });
                            return;
                        }

                        var colModel = colModels[iCol];

                        var editType = colModel.edittype;
                        if (isNullOrUndefinedOrEmpty(editType)) {
                            return;
                        }

                        var data = jqGrid.rowData(rowid);

                        var eventArgs = {
                            cellName: cellname,
                            cellValueBeforeEditing: value,
                            rowData: data,
                            selectOptions : []
                        };

                        //check if column type = year
                        // this type of column is rendred as a select list
                        if (colModel.isYear) {
                            var years = [];
                            var now = new Date();
                            colModel.editrules = colModel.editrules || {};
                            var minYear = colModel.editrules.minValue;
                            var maxYear = colModel.editrules.maxValue;
                            years.addRangeOfIntegers(minYear, maxYear);
                            var itemCount = years.length;
                            for (var i = 0; i < itemCount; i++) {
                                eventArgs.selectOptions.push({
                                    key: years[i],
                                    value : years[i]
                                });
                            } // end for
                            //raise event to enable listeners to inspect and/or to inject values for the select tag
                            onSelectCellRendering(colModel, eventArgs);
                            return;
                        }

                        if (editType === "select") {
                            //raise event to enable listeners to inspect and/or to inject values for the select tag
                            onSelectCellRendering(colModel, eventArgs);
                            return;
                        }

                        //TODO : Process other input types

                    } catch (e) {
                        vpGrid.logException(e);
                    }

                }

                jqGrid.options.afterEditCell = function (rowid, cellname, value, iRow, iCol) {
                    try {
                        jqGrid.currentRowId = rowid;

                        // find the cell
                        var jqGridHost = jqGrid.host();
                        // first step : find the row where the cell is in edit mode
                        var rowSelector = "tr[role=row][id=" + rowid + "]";
                        var jqRow = jqGridHost.find(rowSelector);
                        // second step : find the cell in edit mode
                        var cellSelector = "td[role=gridcell][aria-describedby=" + jqGrid.Id + "_" + cellname + "]";
                        var jqCell = jqRow.find(cellSelector);
                        if (jqCell.notFound()) {
                            vpGrid.logError({
                                message: "Cell not found in DOM. rowid='" + rowid + "'" + "; cellName='" + cellname + "'"
                            });
                        }

                        //third step : find the input element (either input or select or textarea)
                        var jqInput = jqCell.find("input");
                        var jqSelect = jqCell.find("select");
                        var jqTextArea = jqCell.find("textarea");

                        if (jqInput.notFound() && jqSelect.notFound() && jqTextArea.notFound()) {
                            vpGrid.logError({
                                message: "Input element or Select or Textarea not found in DOM. rowid='" + rowid + "'" + "; cellName='" + cellname + "'"
                            });
                            return;
                        }

                        //adjust the width of the input field
                        jqSelect.width(jqSelect.parent().width());
                        jqSelect.addClass('vp-grid-input-field');

                        //Add CSS class for input text field
                        if (jqInput.isInputText()) {
                            jqInput.addClass('vp-grid-input-field');
                        }

                        //adjust overflow for textarea
                        jqTextArea.addClass('vp-grid-input-field');
                        jqTextArea.parent().css('overflow', 'visible');
                        if (jqTextArea.found()) {
                            var test = $('<textarea>');
                            test.css('resize', 'both');

                            if (test.css('resize') !== 'both') {
                                jqTextArea.resizable({
                                    handles: "se"
                                });
                            }
                        }


                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                message: "ColModels not found : rowid='" + rowid + "'" + "; cellName='" + cellname + "'"
                            });
                            return;
                        }

                        var colModel = colModels[iCol];
                        if (isNullOrUndefinedOrEmpty(colModel)) {
                            vpGrid.logError({
                                message: "ColModel not found :  rowid='" + rowid + "'" + "; cellName='" + cellname + "'" + "; iCol='" + iCol + "'"
                            });
                            return;
                        }


                        if (colModel.isAutocomplete) {
                            // input is an autocomplete field
                            //bindEventsOnInputDateEditing(jqInput,rowid iRow, iCol);
                            bindEventsOnInputEditing(jqInput,rowid, iRow, iCol);
                            // bind autocomplete widget
                            jqGrid.options.bindAutocompleteCell(jqInput, value, cellname, iRow, iCol);
                            // do a click to show the full list of autocomplete values
                            executeAsync(this,function () {
                                try {
                                    jqInput.click();
                                } catch (e) {
                                    vpGrid.logException(e);
                                }

                            }, 200);

                            return;
                        }


                        if (colModel.isDate) {
                            // input is a date field
                            bindEventsOnInputDateEditing(jqInput,rowid, iRow, iCol);
                            // bind datepicker widget
                            var datepickerOptions = vpGridOptions.datepickerOptions;
                            if (isNullOrUndefined(datepickerOptions)) {
                                datepickerOptions = {};
                            }
                            //TODO : raise event so that listeners can inspect and/or modifiy datepicker options for this cell

                            // Autosave cell on datepicker closed
                            datepickerOptions.onClose = function (selectedDate) {
                                try {
                                    jqGridHost.jqGrid("saveCell", iRow, iCol);
                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                            };

                            jqInput.datepicker(datepickerOptions);
                            return;
                        }

                        if (colModel.isYear) {
                            bindEventsOnSelectEditing(jqSelect, rowid, iRow, iCol);
                            return;
                        }


                        if (colModel.isSelect) {
                            bindEventsOnSelectEditing(jqSelect, rowid, iRow, iCol);
                            return;
                        }

                        if (colModel.isNote) {
                            bindEventsOnTextAreaEditing(jqTextArea, rowid, iRow, iCol);
                            return;
                        }

                        if (colModel.isInteger) {
                            bindEventsOnIntegerEditing(jqInput, rowid, iRow, iCol);
                            return;
                        }

                        if (colModel.isCurrency) {

                            //TODO : extract following lines into a separate method
                            var customFormatterOptions = {};
                            customFormatterOptions.currency = {};
                            var customCurrencyFormatterOptions = customFormatterOptions.currency;
                            customCurrencyFormatterOptions.decimalSeparator = colModel.formatoptions.decimalSeparator;
                            customCurrencyFormatterOptions.thousandsSeparator = colModel.formatoptions.thousandsSeparator;
                            customCurrencyFormatterOptions.decimalPlaces = colModel.formatoptions.decimalPlaces;

                            var localeValue = $.fn.fmatter("currency", value, customFormatterOptions);
                            //TODO : end extract

                            jqInput.val(localeValue);
                            bindEventsOnCurrencyEditing(jqInput, rowid, iRow, iCol);
                            return;
                        }

                        if (colModel.isNumber) {

                            //TODO : extract following lines into a separate method
                            var customFormatterOptions = {};
                            customFormatterOptions.number = {};
                            var customNumberFormatterOptions = customFormatterOptions.number;
                            customNumberFormatterOptions.decimalSeparator = colModel.formatoptions.decimalSeparator;
                            customNumberFormatterOptions.thousandsSeparator = colModel.formatoptions.thousandsSeparator;
                            customNumberFormatterOptions.decimalPlaces = colModel.formatoptions.decimalPlaces;

                            var localeValue = $.fn.fmatter("number", value, customFormatterOptions);
                            //TODO : end extract

                            jqInput.val(localeValue);
                            bindEventsOnNumberEditing(jqInput, rowid, iRow, iCol);
                            return;
                        }


                        // bind events on other type of inputs (checkbox/text ...)
                        bindEventsOnInputEditing(jqInput, rowid, iRow, iCol);

                    } catch (e) {
                        vpGrid.logException(e);
                    }

                }

                jqGrid.options.beforeSaveCell = function (rowid, cellname, value, iRow, iCol) {
                    try {
                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                message: "ColModels not found : rowid='" + rowid + "'" + "; cellName='" + cellname + "'"
                            });
                            return;
                        }

                        var colModel = colModels[iCol];
                        if (isNullOrUndefinedOrEmpty(colModel)) {
                            vpGrid.logError({
                                message: "ColModel not found :  rowid='" + rowid + "'" + "; cellName='" + cellname + "'" + "; iCol='" + iCol + "'"
                            });
                            return;
                        }

                        var sanitizedValue = value;

                        if (colModel.isCurrency) {
                            //unformat the input value
                            var thousandsSeparator = colModel.formatoptions.thousandsSeparator;
                            var decimalSeparator = colModel.formatoptions.decimalSeparator;
                            sanitizedValue = value.replaceAll(thousandsSeparator, "");
                            sanitizedValue = sanitizedValue.replaceAll(decimalSeparator, '.');
                        }

                        if (colModel.isNumber) {
                            //unformat the input value
                            var thousandsSeparator = colModel.formatoptions.thousandsSeparator;
                            var decimalSeparator = colModel.formatoptions.decimalSeparator;
                            sanitizedValue = value.replaceAll(thousandsSeparator, "");
                            sanitizedValue = sanitizedValue.replaceAll(decimalSeparator, '.');
                        }

                        if (colModel.isInteger) {
                            //unformat the input value
                            var thousandsSeparator = colModel.formatoptions.thousandsSeparator;
                            sanitizedValue = value.replaceAll(thousandsSeparator, "");
                        }

                        //TODO :  raise event
                        var data = jqGrid.rowData(rowid);
                        var eventArgs = {
                            cellName: cellname,
                            cellValue: sanitizedValue,
                            rowData: data
                        };
                        //raise event to enable listeners to inspect and/or to change the value entered by the user
                        onCellUpdating(eventArgs);

                        //check if the eventArgs object has been changed by listeners
                        if (isNullOrUndefinedOrEmpty(eventArgs)) {
                            vpGrid.logError({
                                functionName: "jqGrid.options.beforeSaveCell",
                                message: "eventArgs object corrupted by listener onCellUpdating"
                            });
                            return sanitizedValue;
                        }

                        if (isNotString(eventArgs.cellValue)) {
                            vpGrid.logError({
                                functionName: "jqGrid.options.beforeSaveCell",
                                message: "eventArgs.cellValue object corrupted by listener",
                                info: "listeners on onCellUpdating should return a String type for the eventArgs.cellValue property"
                            });
                            return sanitizedValue;
                        }

                        // take value given by listeners
                        sanitizedValue = eventArgs.cellValue;


                        //if cell is a select element then we must revert the value back to the display value
                        if (colModel.isSelect) {
                            return null;
                        }

                        return sanitizedValue;

                    } catch (e) {
                        vpGrid.logException(e);
                        return value;
                    }
                }

                jqGrid.options.afterSaveCell = function (rowid, cellname, value, iRow, iCol) {
                    try {
                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                functionName: "jqGrid.options.afterSaveCell",
                                message: "ColModels not found : rowid='" + rowid + "'" + "; cellName='" + cellname + "'"
                            });
                            return;
                        }

                        var colModel = colModels[iCol];
                        if (isNullOrUndefinedOrEmpty(colModel)) {
                            vpGrid.logError({
                                message: "ColModel not found :  rowid='" + rowid + "'" + "; cellName='" + cellname + "'" + "; iCol='" + iCol + "'"
                            });
                            return;
                        }

                        //revert back overflow when colModel is Note
                        if (colModel.isNote) {
                            var jqCell = jqGrid.cell(rowid, cellname);
                            jqCell.css('overflow', '');
                        }

                        //update ui-state-error when there is a min/max limitation for value
                        if (jqGrid.cellValueIsInRange(rowid, cellname, value, colModel)) {
                            var jqCell = jqGrid.cell(rowid, cellname);
                            jqCell.removeClass('ui-state-error');
                        }


                        //update data on remote server
                        var data = jqGrid.rowData(rowid);
                        var rowDataBefore = jqGrid.rowData(rowid);
                        jqGrid.updatedData.push(rowDataBefore);
                        jqGrid.updateDataOnRemote();

                        // raise event
                        var eventArgs = {
                            cellName: cellname,
                            cellValue: value,
                            rowid : rowid,
                            rowData: data
                        };

                        //raise event to enable listeners to do additional processing when cell content has been updated
                        onCellUpdated(eventArgs);

                        //update columns that have been changed by the listener
                        var rowDataAfter = eventArgs.rowData;
                        jqGrid.options.updateRow(rowid, cellname,iRow, rowDataBefore, rowDataAfter);

                        //process inline summary rows if needed
                        jqGrid.options.renderInlineSummaryRowsForRow(rowid);

                        //process summary rows if needed
                        jqGrid.options.renderSummaryRowsCell(colModel, true);

                            
                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.options.updateRow = function (rowid, cellname, iRow, rowDataBefore, rowDataAfter) {
                    /// <signature>
                    /// <summary>jqGrid extension (from vpGrid) to update any adjacent cells in row after one cell in this row has been edited</summary>
                    /// <param name="rowid" type="String">The id of the row</param>
                    /// <param name="cellname" type="String">Name of the cell that has been edited. If listener has changed again this cell, the new value for this cell is discarded to avoid loop.</param>
                    /// <param name="iRow" type="Number">The position of the row</param>
                    /// <param name="rowDataBefore" type="Object">Complete row data before the cell was edited</param>
                    /// <param name="rowDataAfter" type="Object">Complete row data after the cell has been edited and after listeners may have changed some cells. </param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        // check if something has changed
                        if (areEquals(rowDataBefore, rowDataAfter)) {
                            return;
                        }

                        for (var p in rowDataBefore) {
                            if (rowDataBefore[p] === rowDataAfter[p]) {
                                continue;
                            }

                            // check the property exists in target object
                            if (rowDataAfter[p] === undefined) {
                                continue;
                            }

                            // do not update again the cell
                            if (p === cellname) {
                                continue;
                            }

                            //check if the cell is the key
                            // -> a key must never be changed
                            var colModel = jqGrid.colModelOf(p);
                            if (colModel.isKey) {
                                vpGrid.logError({
                                    functionName: "jqGrid.options.updateRow",
                                    message: "Cell value has been modified but is defined as primary key. Cell name : '" + p + "' , rowid : '" + rowid + "'",
                                    info: "Check the column schema in your Web Page. Check for the data attribute data-vp-grid-column-type=key"
                                })
                                continue;
                            }
                            
                            //update the cell
                            var newValue = rowDataAfter[p];
                            jqGrid.setCell(rowid, p, newValue);

                            //update the summary cell

                            

                        }

                        jqGrid.updatedData.push(rowDataAfter);
                        jqGrid.updateDataOnRemote();

                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.options.updateRowWithFormData = function (formData) {
                    /// <signature>
                    /// <summary>jqGrid extension (from vpGrid) to update the row after a UI dialog has been submitted by the user.</summary>
                    /// <param name="formData" type="Object">Literal object that contains the values entered/modified by the user.
                    ///                                      Each property in this object must match the name of a column.
                    /// </param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        if (isNullOrUndefinedOrEmpty(formData)) {
                            vpGrid.logError({
                                functionName: "updateRowWithFormData",
                                message: "Input form data is null or empty : '" + formData + "'"
                            });
                            return;
                        }

                        // get the html id of the row to be updated
                        //check if a key has been setup on the Key column
                        var keyColumnName = JQGrid.keyColumnName();
                        if (isNullOrUndefinedOrEmpty(keyColumnName)) {
                            vpGrid.logError({
                                functionName: "updateRowWithFormData",
                                message: "Key column not found.",
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnType + "=key'," + " must be defined int the column schema."
                            });
                            return;
                        }

                        var itemKey = formData[keyColumnName];
                        if (isNullOrUndefinedOrEmpty(itemKey)) {
                            vpGrid.logError({
                                functionName: "updateRowWithFormData",
                                message: "Input form data does not contain a property called : '" + keyColumnName + "'"
                            });
                            return;
                        }

                        if (isNotString(itemKey)) {
                            vpGrid.logError({
                                functionName: "updateRowWithFormData",
                                message: "Input form data property called : '" + keyColumnName + "' must be a string property. Its value is ':" + itemKey + "'"
                            });
                            return;
                        }

                        var jqRow = jqGrid.getRowThatHoldsItemWithKey(itemKey);
                        if (jqRow.notFound()) {
                            vpGrid.logError({
                                functionName: "updateRowWithFormData",
                                message: "Cannot find the htlm table row for the item with key ':" + itemKey + "'"
                            });
                            return;
                        }

                        var rowid = jqRow[0].id;
                        var rowDataBefore = jqGrid.rowData(rowid);
                        var rowDataAfter = $.extend({}, rowDataBefore, formData);
                        
                        // check if something has changed
                        if (areEquals(rowDataBefore, rowDataAfter)) {
                            return;
                        }

                        for (var p in rowDataBefore) {
                            if (rowDataBefore[p] === rowDataAfter[p]) {
                                continue;
                            }

                            // check the property exists in target object
                            if (rowDataAfter[p] === undefined) {
                                continue;
                            }

                            //check if the cell is the key
                            // -> a key must never be changed
                            var colModel = jqGrid.colModelOf(p);
                            if (colModel.isKey) {
                                continue;
                            }

                            //update the cell
                            var newValue = rowDataAfter[p];
                            jqGrid.setCell(rowid, p, newValue);

                            //update the summary cell
                            //TODO : update summary cell -> see afterSaveCell function
                        }

                        jqGrid.updatedData.push(rowDataAfter);
                        jqGrid.updateDataOnRemote();

                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }












                jqGrid.options.afterUpdateInlineSummaryRow = function (rowid, summaryRowid, rowData) {
                    /// <signature>
                    /// <summary>jqGrid extension (from vpGrid) to update cells styling  in an inline summary row after values in this inline row have been modified</summary>
                    /// <param name="rowid" type="String">The id of the row that is linked to the inline summary row.</param>
                    /// <param name="summaryRowid" type="String">The id of the inline summary row</param>
                    /// <param name="rowData" type="Object">Complete row data that was used to update the inline summary row</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        
                        if (isNullOrUndefinedOrEmpty(rowData)) {
                            //TODO : log
                            return;
                        }

                        for (var p in rowData) {
                            if (p.isNotCustomPropertyOf(rowData)) {
                                continue;
                            }
                            var colModel = jqGrid.colModelOf(p);
                            var cellValue = rowData[p];
                            var cellName = colModel.name;

                            //update ui-state-error when there is a min/max limitation for value
                            if (jqGrid.cellValueIsInRange(summaryRowid, cellName, cellValue, colModel)) {
                                var jqCell = jqGrid.inlineSummaryCell(summaryRowid, cellName);
                                jqCell.removeClass('ui-state-error');
                                continue;
                            }

                            if (jqGrid.cellValueIsOutOfRange(summaryRowid, cellName, cellValue, colModel)) {
                                var jqCell = jqGrid.inlineSummaryCell(summaryRowid, cellName);
                                jqCell.addClass('ui-state-error');
                                continue;
                            }
                            

                        }


                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.options.gridComplete = function () {
                    try {
                        jqGrid.filteredItemCount = -1;

                        jqGrid.isReady = true;

                        executeAsync(this, ensureOnlyOneRowCanBeChecked, 150, "ensureOnlyOneRowCanBeChecked");
                        
                        if (jqGrid.filteredItemCount === -1) {
                            updateFilteredItemCount();
                        }
                        executeAsync(this,updateContentPlaceholders, 150,"updateContentPlaceholders");
                        executeAsync(this, jqGrid.options.renderInlineSummaryRows, 100, "renderInlineSummaryRows");
                        executeAsync(this, jqGrid.options.renderSummaryRows, 200, "renderSummaryRows");
                        executeAsync(this, jqGrid.autoInsertNewLineAtBottom, 1000, "autoInsertNewLineAtBottom");
                        
                        if (jqGrid.isEmpty()) {
                            showEmptyMessageOnGridComplete()
                            return;
                        }

                        hideEmptyMessageOnGridComplete();


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.options.afterValidateCell = function (value, colTitle, iCol) {
                    /// <signature>
                    /// <summary>jqGrid extension (from vpGrid) to let listeners do custom validation. This method is called when jqGrid has done its own cell validation</summary>
                    /// <param name="value" type="String">Value of the cell being edited by the user</param>
                    /// <param name="colTitle" type="String">Title of the column's cell</param>
                    /// <param name="iCol" type="Number">Index of the column in the colmodels</param>
                    /// <returns type="Array">Returns an array of values :first value - true or false. The value of true mean that the checking is successful false otherwise; the second value have sense only, if the first value is false, represents the error message which will be displayed to the user. Typically this can look like this [false,”Please enter valid value”]</returns>
                    /// </signature>
                    try {
                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                message: "ColModels not found : afterValidateCell is stopped. colTitle='" + colTitle + "'"
                            });
                            return;
                        }

                        var colModel = colModels[iCol];
                        var cellName = colModel.name;

                        
                        var rowid = jqGrid.currentRowId;
                        var data = null;
                        if (isNotNullOrUndefinedOrEmpty(rowid)) {
                            data = jqGrid.rowData(rowid);
                        }

                        //TODO : check if a modal dialog box is currently opened
                        //          -> if yes : build data object from the FORM input fields of the opened dialog

                        var sanitizedValue = value;
                        var nativeValue = value;

                        if (colModel.isCurrency) {
                            //unformat the input value
                            var thousandsSeparator = colModel.formatoptions.thousandsSeparator;
                            var decimalSeparator = colModel.formatoptions.decimalSeparator;
                            sanitizedValue = value.replaceAll(thousandsSeparator, "");
                            sanitizedValue = sanitizedValue.replaceAll(decimalSeparator, '.');
                            nativeValue = sanitizedValue.toFloat();
                        }

                        if (colModel.isNumber) {
                            //unformat the input value
                            var thousandsSeparator = colModel.formatoptions.thousandsSeparator;
                            var decimalSeparator = colModel.formatoptions.decimalSeparator;
                            sanitizedValue = value.replaceAll(thousandsSeparator, "");
                            sanitizedValue = sanitizedValue.replaceAll(decimalSeparator, '.');
                            nativeValue = sanitizedValue.toFloat();
                        }

                        if (colModel.isInteger) {
                            //unformat the input value
                            var thousandsSeparator = colModel.formatoptions.thousandsSeparator;
                            sanitizedValue = value.replaceAll(thousandsSeparator, "");
                            nativeValue = sanitizedValue.toInt();
                        }

                        var eventArgs = {
                            cellName: cellName,
                            cellValue: sanitizedValue,
                            cellNativeValue : nativeValue,
                            rowData: data,
                            isValid: true,
                            errorMessage: ""
                        };

                        //raise event
                        onCellValidating(eventArgs);

                        if (isNullOrUndefinedOrEmpty(eventArgs)) {
                            vpGrid.logError({
                                functionName: "jqGrid.options.afterValidateCell",
                                message: "eventArgs object corrupted by listener"
                            });
                            return [true, "", ""];
                        }

                        if (isNotBoolean(eventArgs.isValid)) {
                            vpGrid.logError({
                                functionName: "jqGrid.options.afterValidateCell",
                                message: "eventArgs.isValid property corrupted by listener"
                            });
                            return [true, "", ""];;
                        }

                        if (eventArgs.isValid) {
                            return [true, "", ""];
                        }

                        return [false, eventArgs.errorMessage, ""];

                    } catch (e) {
                        vpGrid.logException(e);
                        //fallback to a successfull validation to prevent user being locked inside a cell
                        return [true, "", ""];
                    }
                }

                jqGrid.options.bindAutocompleteCell = function (input, value, cellName, iRow, iCol) {
                    /// <signature>
                    /// <summary>jqGrid extension (from vpGrid) to let listeners configure autocomplete. This method is called when jqGrid is in cell editing mode</summary>
                    /// <param name="input" type="Object">The input DOM element</param>
                    /// <param name="value" type="String">Value of the cell being edited by the user</param>
                    /// <param name="cellname" type="String">Cell name</param>
                    /// <param name="iCol" type="Number">Index of the column in the colmodels</param>
                    /// <returns type="Array">Returns an array of values :first value - true or false. The value of true mean that the checking is successful false otherwise; the second value have sense only, if the first value is false, represents the error message which will be displayed to the user. Typically this can look like this [false,”Please enter valid value”]</returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(input)) {
                            //TODO : log
                            return;
                        }

                        var jqInput = $(input);
                        if (jqInput.notFound()) {
                            //TODO : log
                            return;
                        }

                        var jqInput = $(input);


                        var eventArgs = {
                            cellName: cellName,
                            cellValue: value,
                            options: {},
                            data: []
                        };

                        //raise event
                        onAutocompleteCellRendering(eventArgs);

                        if (isNullOrUndefinedOrEmpty(eventArgs.data)) {
                            eventArgs.data = jqGrid.colValues(cellName);
                        }

                        //TODO : serialize the options object to a data attribute on input element
                        bindAutoCompleteWidgetWithDataOnElement(input, eventArgs.data);

                        // bind to select event to automatically save the cell when an item is selected in the autocomplete list
                        jqInput.on("autocompleteselect", function (event, ui) {
                            try {
                                executeAsync(this,function () {
                                    try {
                                        jqGrid.saveCell(iRow, iCol);
                                    } catch (e) {
                                        vpGrid.logException(e);
                                    }
                                }, 50);


                            } catch (e) {
                                vpGrid.logException(e);
                            }

                        });

                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.options.renderSummaryCell = function (summaryRow,colModel,updateOtherSummaryCells) {
                    /// <signature>
                    /// <summary>jqGrid extension (from vpGrid) to let listeners inject custom content in a summary cell.</summary>
                    /// <param name="summaryRow" type="Object">The table row DOM element that holds the summary row.</param>
                    /// <param name="colModel" type="Object">The column model schema of the column where the summary cell is.</param>
                    /// <param name="updateOtherSummaryCells" type="Boolean">If set to true, a call to method renderMandatorySummaryCells will be done. </param>
                    /// </signature>
                    try {
                        if (jqGrid.options.footerrow === false) {
                            // there is no summary row
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(colModel)) {
                            vpGrid.logError({
                                message: "Cannot render summary cell. colModel object is null or empty."
                            });
                            return;
                        }

                        var cellName = colModel.name;

                        //find UI Identifier
                        var jqSummaryRow = $(summaryRow);
                        var uiIdentifier = jqSummaryRow.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.UIIdentifier,"")

                        var eventArgs = {
                            cellName: cellName,
                            cellValue: "",
                            uiIdentifier : uiIdentifier,
                            useCellFormatter: false,
                            td: {},
                            remove: {}
                        };

                        //raise event to enable listeners set value and attributes on the summary <td> element
                        onSummaryCellRendering(eventArgs);

                        //render summary cell
                        var jqGridHost = jqGrid.host();
                        var userData = {};
                        userData[cellName] = eventArgs.cellValue;
                        var useCellFormatter = eventArgs.useCellFormatter;

                        jqGrid.setFooterData(uiIdentifier, userData, useCellFormatter);

                        //jqGridHost.jqGrid("footerData", "set", userData, useCellFormatter);

                        var jqCell = jqGrid.summaryCell(uiIdentifier,cellName);

                        if (jqCell.notFound()) {
                            vpGrid.logError({
                                message: "Cannot style summary cell. Summary cell not found for column : '" + cellName + "'."
                            });
                            return;
                        }

                        //first remove classes:
                        if (isString(eventArgs.remove['class'])) {
                            var cssClassToBeRemoved = eventArgs.remove['class'];
                            jqCell.removeClass(cssClassToBeRemoved);
                        }

                        //TODO : remove other found attributes

                        if (isString(eventArgs.td.title)) {
                            jqCell.attr('title', eventArgs.td.title.toEncodedHTML());

                        }

                        if (isString(eventArgs.td['class'])) {
                            jqCell.addClass(eventArgs.td['class']);
                        }

                        //if (isString(eventArgs.td.style)) {
                        //    htmlAttributes += (' style="' + eventArgs.td.style + '"');
                        //}

                        //TODO : check if listeners have injected other html attributes

                        if (updateOtherSummaryCells) {
                            jqGrid.options.renderMandatorySummaryCells(summaryRow, cellName);
                        }


                    } catch (e) {
                        vpGrid.logException(e);
                    }

                }

                jqGrid.options.renderSummaryRow = function (element) {
                    /// <signature>
                    /// <summary>jqGrid extension (from vpGrid) to let listeners do custom rendering of a summary row. This method is called when jqGrid is loading or sorting data</summary>
                    /// <param name="element" type="Object">the table row DOM element that holds the summary row.</param>
                    /// </signature>
                    try {

                        if (jqGrid.options.footerrow === false) {
                            // there is no summary row
                            return;
                        }

                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                message: "ColModels not found : renderSummaryRow is stopped."
                            });
                            return;
                        }
                        var colCount = colModels.length;
                        var rowCheckboxIsEnabled = jqGrid.options.multiselect;
                        for (var i = 0; i < colCount; i++) {
                            var colModel = colModels[i];
                            var cellName = colModel.name;
                            if (colModel.hidden) {
                                continue;
                            }

                            if (cellName === "cb" && rowCheckboxIsEnabled) {
                                // no summary on checkbox row cell 
                                // continue;
                            }

                            jqGrid.options.renderSummaryCell(element,colModel,false);

                        }

                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.options.renderMandatorySummaryCells = function (summaryRow, excludedCellName) {
                    /// <signature>
                    /// <summary>Let listeners inject custom content for all adjacent cells that need to computed in the summary row.</summary>
                    /// <param name="summaryRow" type="Object">The table row DOM element that holds the summary row.</param>
                    /// <param name="excludedCellName" type="Object">Name of the summary cell whose content has already been set by listeners.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                functionName: "jqGrid.options.renderMandatorySummaryCells",
                                message: "ColModels not found."
                            });
                            return;
                        }

                        var colsCount = colModels.length;
                        for (var i = 0; i < colsCount; i++) {
                            var colModel = colModels[i];
                            if (colModel.name === excludedCellName) {
                                continue;
                            }

                            if (colModel.alwaysUpdateSummaryCell === true) {
                                // always call with false to prevent looping
                                jqGrid.options.renderSummaryCell(summaryRow,colModel, false);
                            }

                        }

                        
                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.options.renderSummaryRows = function () {
                    /// <signature>
                    /// <summary>jqGrid extension (from vpGrid) to let listeners do custom rendering of any summary row. 
                    ///     This method is called when jqGrid is loading or sorting data.
                    /// </summary>
                    /// </signature>
                    try {

                        if (jqGrid.options.footerrow === false) {
                            // there is no summary row
                            return;
                        }

                        var jqSummaryRows = jqGrid.summaryRows();
                        if (jqSummaryRows.notFound()) {
                            vpGrid.logError({
                                message: "Summary rows not found : renderSummaryRows is stopped."
                            });
                            return;
                        }

                        var summaryRowCount = jqSummaryRows.length;
                        
                        for (var i = 0; i < summaryRowCount; i++) {
                            var summaryRow = jqSummaryRows[i];
                            jqGrid.options.renderSummaryRow(summaryRow);
                        }

                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.options.renderSummaryRowsCell = function (colModel, updateOtherSummaryCells) {
                    /// <signature>
                    /// <summary>jqGrid extension (from vpGrid) to let listeners inject custom content in a summary cell in all related summary rows.</summary>
                    /// <param name="colModel" type="Object">The column model schema of the column where the summary cell is.</param>
                    /// <param name="updateOtherSummaryCells" type="Boolean">If set to true, a call to method renderMandatorySummaryCells will be done. </param>
                    /// </signature>
                    try {
                        if (jqGrid.options.footerrow === false) {
                            // there is no summary row
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(colModel)) {
                            vpGrid.logError({
                                message: "Cannot render summary cell. colModel object is null or empty."
                            });
                            return;
                        }

                        var cellName = colModel.name;

                        var jqSummaryRows = jqGrid.summaryRows();
                        var summaryRowsCount = jqSummaryRows.length;
                        for (var i = 0; i < summaryRowsCount; i++) {
                            var summaryRow = jqSummaryRows[i];
                            jqGrid.options.renderSummaryCell(summaryRow, colModel, updateOtherSummaryCells);

                        }


                    } catch (e) {
                        vpGrid.logException(e);
                    }

                }

                jqGrid.options.renderInlineSummaryRows = function () {
                    /// <signature>
                    /// <summary>jqGrid extension (from vpGrid) to let listeners insert inline summary rows. This method is called when jqGrid is loaded or sorted data</summary>
                    /// </signature>
                    try {

                        //get all rowids
                        var jqGridHost = jqGrid.host();
                        
                        var inGridRowIds = jqGridHost.jqGrid("getDataIDs");
                        if (isNullOrUndefinedOrEmpty(inGridRowIds)) {
                            // nothing to do
                            return;
                        }

                        var rowsCount = inGridRowIds.length;
                        for (var i = 0; i < rowsCount; i++) {
                            var rowid = inGridRowIds[i];
                            jqGrid.options.renderInlineSummaryRowsForRow(rowid);

                        }


                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.options.renderInlineSummaryRowsForRow = function (rowid) {
                    /// <signature>
                    /// <summary>jqGrid extension (from vpGrid) to let listeners insert/update inline summary rows. This method is called after a cell has been updated in row identified by rowid.</summary>
                    /// <param name="rowid" type="String">Dom id of the row. Each row in a grid may have between 0 and N inline summary row associated to it.</param>
                    /// </signature>
                    try {
                        if (isNotString(rowid)) {
                            vpGrid.logError({
                                functionName: "jqGrid.options.renderInlineSummaryRowsForRow",
                                message: "rowid is not valid string :'" + rowid + "'"
                            });
                            return;
                        }

                        //TODO : check rowid is an existing row

                        var rowData = jqGrid.rowData(rowid);
                        var eventArgs = {
                            rowid: rowid,
                            rowData: rowData
                        };

                        //raise event
                        onInlineSummaryRowRendering(eventArgs);

                      

                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.autoInsertNewLineAtBottom = function () {
                    /// <signature>
                    /// <summary>Automatically adds a new empty line at he bottom of the grid.
                    /// This new line is added only if : 
                    ///                 - jqGrid.options.autoInsertNewLineAtBottom = true
                    ///                 - User is currently editing the last line in the grid
                    ///                 - there is no empty line already available at the bottom of the grid
                    ///</summary>
                    /// </signature>
                    try {
                        if (jqGrid.options.autoInsertNewLineAtBottom === false) {
                            return;
                        }

                        if (jqGrid.isEmpty()) {
                            var emptyRowData = jqGrid.emptyRowData();
                            // TODO : feed emptyRowData with default values set from colmodel
                            jqGrid.insertNewRow(emptyRowData, 'last');

                            return;
                        }

                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }



                jqGrid.restoreCell = function (iRow, iCol) {
                    try {
                        var jqGridHost = jqGrid.host();
                        jqGridHost.jqGrid("restoreCell", iRow, iCol);

                        //restore overflow css property on note column
                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                functionName: "jqGrid.restoreCell",
                                message: "ColModels not found : iRow='" + iRow + "'" + "; iCol='" + iCol + "'"
                            });
                            return;
                        }

                        var colModel = colModels[iCol];
                        if (isNullOrUndefinedOrEmpty(colModel)) {
                            vpGrid.logError({
                                functionName: "jqGrid.restoreCell",
                                message: "colModel not found : iRow='" + iRow + "'" + "; iCol='" + iCol + "'"
                            });
                            return;
                        }


                        //revert back overflow when colModel is Note
                        if (colModel.isNote) {
                            //TODO : check that rowid = iRow
                            var jqCell = jqGrid.cell(iRow, colModel.name);
                            jqCell.css('overflow', '');
                        }

                    } catch (e) {
                        vpGrid.logException(e);
                    }

                }

                jqGrid.saveCell = function (iRow, iCol) {
                    try {
                        var jqGridHost = jqGrid.host();
                        jqGridHost.jqGrid("saveCell", iRow, iCol);
                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function onCellValidating(eventArgs) {
                    try {

                        EventHandlers.raiseEvent(vpGrid.Event.onCellValidating, vpGrid, eventArgs);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function updateContentPlaceholders() {
                    try {
                        var jqGridContainer = jqGrid.container();
                        var elementsSelector = "[" + vpGrid.HtmlDataTag.UIContentPlaceholder + "=true]";
                        var jqElements = jqGridContainer.find(elementsSelector);
                        if (jqElements.notFound()) {
                            //TODO : log info
                            return;
                        }

                        // step 2 : take only elements that must be processed in this specific timeline sequence
                        var elementsCount = jqElements.length;
                        for (var i = 0; i < elementsCount; i++) {
                            var element = jqElements[i];

                            fillContentPlaceholderOnElement(element);
                        }
                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function updateFilteredItemCount() {
                    try {
                        var itemCount = jqGrid.rows.length - 1;
                        jqGrid.filteredItemCount = itemCount;

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.imageFormatter = function (cellValue, options, rowObject) {
                    try {
                        if (isNullOrUndefinedOrEmpty(cellValue)) {
                            cellValue = "";
                        }

                        var colModel = options.colModel;
                        var cellName = colModel.name;
                        var data = rowObject;

                        var eventArgs = {
                            cellName: cellName,
                            cellValue: cellValue,
                            rowData: data,
                            img: {
                                alt: cellValue,
                                title: cellValue,
                                src: ""
                            }
                        };

                        //raise event to enable listeners to inspect and/or to inject values for the attributes of image tag
                        onImageCellRendering(eventArgs);

                        //check if the src attribute has been setup
                        if (isNullOrUndefinedOrEmpty(eventArgs)) {
                            vpGrid.logError({
                                functionName: "jqGrid.imageFormatter",
                                message: "eventArgs object corrupted by listener"
                            });
                            return "";
                        }

                        if (isNullOrUndefinedOrEmpty(eventArgs.img)) {
                            vpGrid.logError({
                                functionName: "jqGrid.imageFormatter",
                                message: "eventArgs.img object corrupted by listener"
                            });
                            return "";
                        }

                        if (isNullOrUndefinedOrEmpty(eventArgs.img.src)) {
                            return "";
                        }

                        //TODO : log if img.alt attribute has been changed

                        //render the img tag
                        var image = $("<img>", eventArgs.img);
                        var span = $('<span>');
                        var wrappedImage = image.appendTo(span);
                        return wrappedImage.parent().html();


                    } catch (e) {
                        vpGrid.logException(e);
                        return "";
                    }
                }

                jqGrid.imageUnformatter = function (cellValue, options, cell) {
                    try {
                        var jqCell = $(cell);
                        var jqImage = jqCell.find('img');
                        var altvalue = jqImage.toStringOrDefaultFromAttribute("alt", "");
                        return altvalue;

                    } catch (e) {
                        vpGrid.logException(e);
                        return cellValue;
                    }
                }

                jqGrid.linkFormatter = function (cellValue, options, rowObject) {
                    try {
                        if (isNullOrUndefinedOrEmpty(cellValue)) {
                            cellValue = "";
                        }

                        var colModel = options.colModel;
                        var cellName = colModel.name;
                        var data = rowObject;

                        var target = "_vpTab";
                        var formatOptions = colModel.formatOptions || {};
                        if (isNotNullOrUndefinedOrEmpty(formatOptions.target)) {
                            target = formatOptions.target;
                        }

                        //extract link content
                        var linkContent = cellValue.leafName();

                        var eventArgs = {
                            cellName: cellName,
                            cellValue: cellValue,
                            rowData: data,
                            a: {
                                href: cellValue,
                                title: cellValue,
                                target: target
                            },
                            html: linkContent
                        };

                        //raise event to enable listeners to inspect and/or to inject values for the attributes of <a> tag
                        onLinkCellRendering(eventArgs);

                        //check if the src attribute has been setup
                        if (isNullOrUndefinedOrEmpty(eventArgs)) {
                            vpGrid.logError({
                                functionName: "jqGrid.linkFormatter",
                                message: "eventArgs object corrupted by listener"
                            });
                            return "";
                        }

                        if (isNullOrUndefinedOrEmpty(eventArgs.a)) {
                            vpGrid.logError({
                                functionName: "jqGrid.linkFormatter",
                                message: "eventArgs.a object corrupted by listener"
                            });
                            return "";
                        }

                        //TODO : log if a.href attribute has been changed

                        if (isNullOrUndefinedOrEmpty(eventArgs.a.href)) {
                            return "";
                        }

                        //TODO : log if eventArgs.html attribute has been changed
                        if (isNullOrUndefinedOrEmpty(eventArgs.html)) {
                            return "";
                        }

                        //render the a tag
                        var link = $("<a>", eventArgs.a);
                        link.html(eventArgs.html)
                        var span = $('<span>');
                        var wrappedLink = link.appendTo(span);
                        return wrappedLink.parent().html();

                    } catch (e) {
                        vpGrid.logException(e);
                        return "";
                    }
                }

                jqGrid.linkUnformatter = function (cellValue, options, cell) {
                    try {
                        var jqCell = $(cell);
                        var jqLink = jqCell.find('a');
                        var hrefValue = jqLink.toStringOrDefaultFromAttribute("href", "");
                        return hrefValue;

                    } catch (e) {
                        vpGrid.logException(e);
                        return cellValue;
                    }
                }

                jqGrid.cannotDeleteItemFormatter = function (cellValue, options, rowObject) {
                    try {
                        if (isNullOrUndefinedOrEmpty(cellValue)) {
                            cellValue = "";
                        }
                        
                        var colModel = options.colModel;
                        var cellName = colModel.name;
                        var data = rowObject;

                        //render the cannot delete button
                        var divButton = $("<div>");
                        divButton.addClass("vp-grid-button-delete");
                        $("<span>").addClass("ui-icon ui-icon-link").appendTo(divButton);

                        //divButton.click(showDeleteItemMessage);

                        var span = $('<span>');
                        var wrappedDiv = divButton.appendTo(span);
                        return wrappedDiv.parent().html();

                    } catch (e) {
                        vpGrid.logException(e);
                        return "";
                    }
                }


                jqGrid.deleteItemFormatter = function (cellValue, options, rowObject) {
                    try {
                        if (isNullOrUndefinedOrEmpty(cellValue)) {
                            cellValue = "";
                        }

                        var colModel = options.colModel;
                        var cellName = colModel.name;
                        var data = rowObject;

                        //check if the row is deletable
                        var isDeletable = false;
                        var isDeletableColName = jqGrid.deleteActionValidatorColumnName();
                        if (isNotNullOrUndefinedOrEmpty(isDeletableColName)) {
                            isDeletable = data[isDeletableColName];
                        }

                        if (isNullOrUndefinedOrEmpty(isDeletable)) {
                            // by default a row cannot be deleted
                            return  jqGrid.cannotDeleteItemFormatter(cellValue, options, rowObject);
                            
                        }

                        if (isNotBoolean(isDeletable)) {
                            // by default a row cannot be deleted
                            return jqGrid.cannotDeleteItemFormatter(cellValue, options, rowObject);
                            
                        }

                        if (isDeletable === false) {
                            // by default a row cannot be deleted
                            return jqGrid.cannotDeleteItemFormatter(cellValue, options, rowObject);
                            
                        }

                        //TODO : raise event to ask listener if the row can be deleted

                        //render the delete button
                        var divButton = $("<div>");
                        divButton.addClass("vp-grid-button-delete");
                        $("<span>").addClass("ui-icon ui-icon-trash").appendTo(divButton);
                        
                        //divButton.click(showDeleteItemMessage);

                        var span = $('<span>');
                        var wrappedDiv = divButton.appendTo(span);
                        return wrappedDiv.parent().html();

                    } catch (e) {
                        vpGrid.logException(e);
                        return "";
                    }
                }

                jqGrid.deleteItemUnformatter = function (cellValue, options, cell) {
                    try {
                        var jqCell = $(cell);
                        return cellValue;

                    } catch (e) {
                        vpGrid.logException(e);
                        return cellValue;
                    }
                }

                function onCellRendering(eventArgs) {
                    try {
                        // make a backup copy of eventArgs
                        var eventArgsCopy = $.extend({}, eventArgs);

                        EventHandlers.raiseEvent(vpGrid.Event.onCellRendering, vpGrid, eventArgs);

                        // check possible misbehavior from listeners
                        if (isNullOrUndefinedOrEmpty(eventArgs)) {
                            vpGrid.logError({
                                functionName: "onCellRendering",
                                message: "eventArgs object corrupted by listener",
                                info: "eventArgs object is reverted to its original state"
                            });
                            $.extend(eventArgs, eventArgsCopy);
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(eventArgs.td)) {
                            eventArgs.td = eventArgsCopy.td;
                        }


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function onSummaryCellRendering(eventArgs) {
                    try {
                        // make a backup copy of eventArgs
                        var eventArgsCopy = $.extend({}, eventArgs);

                        EventHandlers.raiseEvent(vpGrid.Event.onSummaryCellRendering, vpGrid, eventArgs);

                        // check possible misbehavior from listeners
                        if (isNullOrUndefinedOrEmpty(eventArgs)) {
                            vpGrid.logError({
                                functionName: "onSummaryCellRendering",
                                message: "eventArgs object corrupted by listener",
                                info: "eventArgs object is reverted to its original state"
                            });
                            $.extend(eventArgs, eventArgsCopy);
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(eventArgs.td)) {
                            eventArgs.td = eventArgsCopy.td;
                        }

                        if (isNullOrUndefinedOrEmpty(eventArgs.remove)) {
                            eventArgs.remove = eventArgsCopy.remove;
                        }

                        if (isNullOrUndefinedOrEmpty(eventArgs.cellValue)) {
                            eventArgs.cellValue = "";
                        }

                        if (isNotBoolean(eventArgs.useCellFormatter)) {
                            eventArgs.useCellFormatter = false;
                        }


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function onImageCellRendering(eventArgs) {
                    try {

                        EventHandlers.raiseEvent(vpGrid.Event.onImageCellRendering, vpGrid, eventArgs);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function onLinkCellRendering(eventArgs) {
                    try {

                        EventHandlers.raiseEvent(vpGrid.Event.onLinkCellRendering, vpGrid, eventArgs);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function onAutocompleteCellRendering(eventArgs) {
                    try {
                        // make a backup copy of eventArgs
                        var eventArgsCopy = $.extend({}, eventArgs);

                        EventHandlers.raiseEvent(vpGrid.Event.onAutocompleteCellRendering, vpGrid, eventArgs);

                        // check possible misbehavior from listeners
                        if (isNullOrUndefinedOrEmpty(eventArgs)) {
                            vpGrid.logError({
                                functionName: "onAutocompleteCellRendering",
                                message: "eventArgs object corrupted by listener",
                                info: "eventArgs object is reverted to its original state"
                            });
                            $.extend(eventArgs, eventArgsCopy);
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(eventArgs.options)) {
                            eventArgs.options = eventArgsCopy.options;
                        }

                        if (isNullOrUndefinedOrEmpty(eventArgs.data)) {
                            eventArgs.data = eventArgsCopy.data;
                        }

                        if (isNotArray(eventArgs.data)) {
                            vpGrid.logError({
                                functionName: "onAutocompleteCellRendering",
                                message: "eventArgs.data array corrupted by listener",
                                info: "eventArgs.data is reverted to its original state"
                            });
                            eventArgs.data = eventArgsCopy.data;
                        }


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function onCellUpdating(eventArgs) {
                    try {

                        EventHandlers.raiseEvent(vpGrid.Event.onCellUpdating, vpGrid, eventArgs);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function onCellUpdated(eventArgs) {
                    try {

                        EventHandlers.raiseEvent(vpGrid.Event.onCellUpdated, vpGrid, eventArgs);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function onInlineSummaryRowRendering(eventArgs) {
                    try {

                        EventHandlers.raiseEvent(vpGrid.Event.onInlineSummaryRowRendering, vpGrid, eventArgs);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.defaultCurrencyFormatOptions = function () {
                    try {

                        var formatOptions = $.jgrid.formatter.currency;
                        return formatOptions;

                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }
                }

                jqGrid.defaultNumberFormatOptions = function () {
                    try {

                        var formatOptions = $.jgrid.formatter.number;
                        return formatOptions;

                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }
                }

                function bindEventsOnInputDateEditing(input,rowid, iRow, iCol) {
                    /// <signature>
                    /// <summary>Bind events on the input field of the cell that is currently in edition mode.
                    /// The binded events enable :
                    ///             correct management of the cell content when the cell is in edition mode,
                    ///             smooth user experience when user navigate outside the cell he is currently editing
                    /// </summary>
                    /// <param name="input" type="Object">jQuery Object that points to the input field.</param>
                    /// <param name="rowid" type="String">Dom id of the row corresponding to this cell</param>
                    /// <param name="iRow" type="Number">Index of the same row in the table DOM element.</param>
                    /// <param name="iCol" type="Number">Index of the column of the editing cell.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(input)) {
                            //TODO : log
                            return;
                        }

                        var jqInput = $(input);
                        if (jqInput.notFound()) {
                            //TODO : log
                            return;
                        }

                        var jqGridHost = jqGrid.host();

                        //unbind events bound by jqGrid
                        jqInput.unbind("keydown");

                        // re-bind the keydown event with our implementation
                        //backup original value
                        var originalValue = jqInput.val();

                        jqInput.bind("keydown", function (e) {
                            try {
                                // case Escape
                                if (e.keyCode === 27) {
                                    //hide the datepicker
                                    hideWidgetOnElement(this);
                                    //jqGridHost.jqGrid("restoreCell", iRow, iCol);
                                    jqGridHost.jqGrid("setCell", rowid, iCol, originalValue, false, false, true);

                                    return false;
                                }

                                // case ENTER
                                if (e.keyCode === 13) {
                                    hideWidgetOnElement(this);
                                    jqGridHost.jqGrid("saveCell", iRow, iCol);
                                    return false;
                                }

                                // case TAB
                                if (e.keyCode === 9) {
                                    //TODO : check if cell has been modified
                                    hideWidgetOnElement(this);
                                    jqGridHost.jqGrid("saveCell", iRow, iCol);

                                    //case Shift TAB
                                    if (e.shiftKey) {
                                        jqGridHost.jqGrid("prevCell", iRow, iCol);
                                        return false;
                                    }

                                    jqGridHost.jqGrid("nextCell", iRow, iCol);
                                    return false;
                                }


                            } catch (ex) {
                                vpGrid.logException(ex);
                            }
                            finally {
                                e.stopPropagation();
                            }
                        });


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function bindEventsOnSelectEditing(input,rowid, iRow, iCol) {
                    /// <signature>
                    /// <summary>Bind events on the select field of the cell that is currently in edition mode.
                    /// The binded events enable :
                    ///             correct management of the cell content when the cell is in edition mode,
                    ///             smooth user experience when user navigate outside the cell he is currently editing
                    /// </summary>
                    /// <param name="input" type="Object">jQuery Object that points to the input field.</param>
                    /// <param name="rowid" type="String">Dom id of the row corresponding to this cell</param>
                    /// <param name="iRow" type="Number">Index of the same row in the table DOM element.</param>
                    /// <param name="iCol" type="Number">Index of the column of the editing cell.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(input)) {
                            //TODO : log
                            return;
                        }

                        var jqInput = $(input);
                        if (jqInput.notFound()) {
                            //TODO : log
                            return;
                        }

                        var jqGridHost = jqGrid.host();

                        //unbind events bound by jqGrid
                        jqInput.unbind("keydown");

                        // re-bind the keydown event with our implementation
                        jqInput.bind("keydown", function (e) {
                            try {
                                // case Escape
                                if (e.keyCode === 27) {
                                    jqGridHost.jqGrid("restoreCell", iRow, iCol);
                                    return false;
                                }

                                // case ENTER
                                if (e.keyCode === 13) {
                                    jqGridHost.jqGrid("saveCell", iRow, iCol);
                                    return false;
                                }

                                // case TAB
                                if (e.keyCode === 9) {
                                    jqGridHost.jqGrid("saveCell", iRow, iCol);
                                    //case Shift TAB
                                    if (e.shiftKey) {
                                        jqGridHost.jqGrid("prevCell", iRow, iCol);
                                        return false;
                                    }

                                    jqGridHost.jqGrid("nextCell", iRow, iCol);
                                    return false;
                                }

                                // case KeyUP
                                if (e.keyCode === 38) {
                                    // do nothing (user wants to select an option with the up/dow key
                                    // we must prevent the onchange event in this case
                                    $(this).unbind('change');
                                    return true;
                                }

                                // case Key Down
                                if (e.keyCode === 40) {
                                    // do nothing (user wants to select an option with the up/dow key
                                    // we must prevent the onchange event in this case
                                    $(this).unbind('change');
                                    return true;
                                }

                                // case left arrow
                                if (e.keyCode === 37) {
                                    // do nothing (user wants to select an option with the up/dow key
                                    return false;
                                }

                                // case right arrow
                                if (e.keyCode === 39) {
                                    // do nothing (user wants to select an option with the up/dow key
                                    return false;
                                }

                            } catch (ex) {
                                vpGrid.logException(ex);
                            }
                            finally {
                                e.stopPropagation();
                            }
                        });

                        jqInput.bind('blur', function () {
                            try {
                                jqGridHost.jqGrid("saveCell", iRow, iCol);
                                // Prevent default action
                                return false;

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });

                        //automaticall save the cell when an option has been selected in the Select element
                        jqInput.bind('change', function () {
                            try {
                                jqGridHost.jqGrid("saveCell", iRow, iCol);

                                // Prevent default action
                                return false;

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function bindEventsOnTextAreaEditing(input,rowid, iRow, iCol) {
                    /// <signature>
                    /// <summary>Bind events on the TextArea field of the cell that is currently in edition mode.
                    /// The binded events enable :
                    ///             correct management of the cell content when the cell is in edition mode,
                    ///             smooth user experience when user navigate outside the cell he is currently editing
                    /// </summary>
                    /// <param name="input" type="Object">jQuery Object that points to the input field.</param>
                    /// <param name="rowid" type="String">Dom id of the row corresponding to this cell</param>
                    /// <param name="iRow" type="Number">Index of the same row in the table DOM element.</param>
                    /// <param name="iCol" type="Number">Index of the column of the editing cell.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(input)) {
                            //TODO : log
                            return;
                        }

                        var jqInput = $(input);
                        if (jqInput.notFound()) {
                            //TODO : log
                            return;
                        }

                        var jqGridHost = jqGrid.host();

                        //unbind events bound by jqGrid
                        jqInput.unbind("keydown");

                        // re-bind the keydown event with our implementation
                        jqInput.bind("keydown", function (e) {
                            try {
                                // case Escape
                                if (e.keyCode === 27) {
                                    //jqGridHost.jqGrid("restoreCell", iRow, iCol);
                                    jqGrid.restoreCell(iRow, iCol);
                                    return false;
                                }

                                // case ENTER
                                if (e.keyCode === 13) {
                                    //do nothing
                                    //jqGridHost.jqGrid("saveCell", iRow, iCol);
                                    return true;
                                }

                                // case TAB
                                if (e.keyCode === 9) {
                                    jqGridHost.jqGrid("saveCell", iRow, iCol);
                                    //case Shift TAB
                                    if (e.shiftKey) {
                                        jqGridHost.jqGrid("prevCell", iRow, iCol);
                                        return false;
                                    }

                                    jqGridHost.jqGrid("nextCell", iRow, iCol);
                                    return false;
                                }


                                // case KeyUP
                                if (e.keyCode === 38) {
                                    // do nothing (user wants to navigate in the text with the up/dow key
                                    return true;
                                }

                                // case Key Down
                                if (e.keyCode === 40) {
                                    // do nothing (user wants to select an option with the up/dow key
                                    return true;
                                }

                                // case left arrow
                                if (e.keyCode === 37) {
                                    // do nothing (user wants to select an option with the up/dow key
                                    return true;
                                }

                                // case right arrow
                                if (e.keyCode === 39) {
                                    // do nothing (user wants to select an option with the up/dow key
                                    return true;
                                }

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                            finally {
                                e.stopPropagation();
                            }
                        });

                        jqInput.bind('blur', function () {
                            try {
                                jqGridHost.jqGrid("saveCell", iRow, iCol);
                                // Prevent default action
                                return false;

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });



                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function bindEventsOnCurrencyEditing(input,rowid, iRow, iCol) {
                    /// <signature>
                    /// <summary>Bind events on the input field of the cell that is currently in edition mode.
                    /// The binded events enable :
                    ///             correct management of the cell content when the cell is in edition mode,
                    ///             smooth user experience when user navigate outside the cell he is currently editing
                    /// </summary>
                    /// <param name="input" type="Object">jQuery Object that points to the input field.</param>
                    /// <param name="rowid" type="String">Dom id of the row corresponding to this cell</param>
                    /// <param name="iRow" type="Number">Index of the same row in the table DOM element.</param>
                    /// <param name="iCol" type="Number">Index of the column of the editing cell.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(input)) {
                            //TODO : log
                            return;
                        }

                        var jqInput = $(input);
                        if (jqInput.notFound()) {
                            //TODO : log
                            return;
                        }

                        var jqGridHost = jqGrid.host();

                        jqInput.bind('blur', function () {
                            try {
                                jqGridHost.jqGrid("saveCell", iRow, iCol);
                                // Prevent default action
                                return false;

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });



                        //unbind events bound by jqGrid
                        jqInput.unbind("keypress");

                        // re-bind the keydown event with our implementation
                        jqInput.bind("keypress", function (e) {
                            try {

                                var keyCode = e.which;
                                
                                if (keyCode === 48) { //0
                                    return true;
                                }
                                if (keyCode === 49) { //1
                                    return true;
                                }
                                if (keyCode === 50) { //2
                                    return true;
                                }
                                if (keyCode === 51) { //3
                                    return true;
                                }
                                if (keyCode === 52) { //4
                                    return true;
                                }
                                if (keyCode === 53) { //5
                                    return true;
                                }
                                if (keyCode === 54) { //6
                                    return true;
                                }
                                if (keyCode === 55) { //7
                                    return true;
                                }
                                if (keyCode === 56) { //8
                                    return true;
                                }
                                if (keyCode === 57) { //9
                                    return true;
                                }
                                if (keyCode === 8) { //backspace
                                    return true;
                                }

                                if (keyCode === 32) { //space
                                    return true;
                                }

                                if (keyCode === 44) { //comma
                                    return true;
                                }

                                if (keyCode === 46) { //point
                                    return true;
                                }

                                if (keyCode === 45) { //-
                                    return true;
                                }

                                return false;

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                            finally {
                                e.stopPropagation();
                            }
                        });


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function bindEventsOnNumberEditing(input,rowid, iRow, iCol) {
                    /// <signature>
                    /// <summary>Bind events on the input field of the cell that is currently in edition mode.
                    /// The binded events enable :
                    ///             correct management of the cell content when the cell is in edition mode,
                    ///             smooth user experience when user navigate outside the cell he is currently editing
                    /// </summary>
                    /// <param name="rowid" type="String">Dom id of the row corresponding to this cell</param>
                    /// <param name="iRow" type="Number">Index of the same row in the table DOM element.</param>
                    /// <param name="iCol" type="Number">Index of the column of the editing cell.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(input)) {
                            //TODO : log
                            return;
                        }

                        var jqInput = $(input);
                        if (jqInput.notFound()) {
                            //TODO : log
                            return;
                        }

                        var jqGridHost = jqGrid.host();

                        jqInput.bind('blur', function () {
                            try {
                                jqGridHost.jqGrid("saveCell", iRow, iCol);
                                // Prevent default action
                                return false;

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });


                        //unbind events bound by jqGrid
                        jqInput.unbind("keypress");

                        // re-bind the keydown event with our implementation
                        jqInput.bind("keypress", function (e) {
                            try {

                                var keyCode = e.which;
                                if (keyCode === 48) { //0
                                    return true;
                                }
                                if (keyCode === 49) { //1
                                    return true;
                                }
                                if (keyCode === 50) { //2
                                    return true;
                                }
                                if (keyCode === 51) { //3
                                    return true;
                                }
                                if (keyCode === 52) { //4
                                    return true;
                                }
                                if (keyCode === 53) { //5
                                    return true;
                                }
                                if (keyCode === 54) { //6
                                    return true;
                                }
                                if (keyCode === 55) { //7
                                    return true;
                                }
                                if (keyCode === 56) { //8
                                    return true;
                                }
                                if (keyCode === 57) { //9
                                    return true;
                                }
                                if (keyCode === 8) { //backspace
                                    return true;
                                }

                                if (keyCode === 32) { //space
                                    return true;
                                }

                                if (keyCode === 44) { //comma
                                    return true;
                                }

                                if (keyCode === 46) { //point
                                    return true;
                                }

                                if (keyCode === 45) { //-
                                    return true;
                                }

                                return false;

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                            finally {
                                e.stopPropagation();
                            }
                        });


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function bindEventsOnIntegerEditing(input,rowid, iRow, iCol) {
                    /// <signature>
                    /// <summary>Bind events on the input field of the cell that is currently in edition mode.
                    /// The binded events enable :
                    ///             correct management of the cell content when the cell is in edition mode,
                    ///             smooth user experience when user navigate outside the cell he is currently editing
                    /// </summary>
                    /// <param name="input" type="Object">jQuery Object that points to the input field.</param>
                    /// <param name="rowid" type="String">Dom id of the row corresponding to this cell</param>
                    /// <param name="iRow" type="Number">Index of the same row in the table DOM element.</param>
                    /// <param name="iCol" type="Number">Index of the column of the editing cell.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(input)) {
                            //TODO : log
                            return;
                        }

                        var jqInput = $(input);
                        if (jqInput.notFound()) {
                            //TODO : log
                            return;
                        }

                        var jqGridHost = jqGrid.host();

                        jqInput.bind('blur', function () {
                            try {
                                jqGridHost.jqGrid("saveCell", iRow, iCol);
                                // Prevent default action
                                return false;

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });

                        //unbind events bound by jqGrid
                        jqInput.unbind("keypress");

                        // re-bind the keydown event with our implementation
                        jqInput.bind("keypress", function (e) {
                            try {

                                var keyCode = e.which;
                                if (keyCode === 48) { //0
                                    return true;
                                }
                                if (keyCode === 49) { //1
                                    return true;
                                }
                                if (keyCode === 50) { //2
                                    return true;
                                }
                                if (keyCode === 51) { //3
                                    return true;
                                }
                                if (keyCode === 52) { //4
                                    return true;
                                }
                                if (keyCode === 53) { //5
                                    return true;
                                }
                                if (keyCode === 54) { //6
                                    return true;
                                }
                                if (keyCode === 55) { //7
                                    return true;
                                }
                                if (keyCode === 56) { //8
                                    return true;
                                }
                                if (keyCode === 57) { //9
                                    return true;
                                }
                                if (keyCode === 8) { //backspace
                                    return true;
                                }
                                if (keyCode === 45) { //-
                                    return true;
                                }

                                return false;

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                            finally {
                                e.stopPropagation();
                            }
                        });


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function bindEventsOnInputEditing(input, rowid, iRow, iCol) {
                    /// <signature>
                    /// <summary>Bind events on the input field of the cell that is currently in edition mode.
                    /// The binded events enable :
                    ///             correct management of the cell content when the cell is in edition mode,
                    ///             smooth user experience when user navigate outside the cell he is currently editing
                    /// </summary>
                    /// <param name="input" type="Object">jQuery Object that points to the input field.</param>
                    /// <param name="rowid" type="String">Dom id of the row corresponding to this cell</param>
                    /// <param name="iRow" type="Number">Index of the row in the table DOM element.</param>
                    /// <param name="iCol" type="Number">Index of the column of the editing cell.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(input)) {
                            //TODO : log
                            return;
                        }

                        var jqInput = $(input);
                        if (jqInput.notFound()) {
                            //TODO : log
                            return;
                        }

                        var jqGridHost = jqGrid.host();

                        jqInput.bind('blur', function () {
                            try {
                                jqGridHost.jqGrid("saveCell", iRow, iCol);
                                // Prevent default action
                                return false;

                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function onSelectCellRendering(colModel, eventArgs) {
                    try {

                        if (isNullOrUndefined(colModel)) {
                            //TODO : log
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(eventArgs)) {
                            //TODO : log
                            return;
                        }

                        //eventArgs.selectOptions = [];

                        EventHandlers.raiseEvent(vpGrid.Event.onSelectCellRendering, vpGrid, eventArgs);

                        //check if new select options have been passed by the listener(s)
                        if (isNullOrUndefinedOrEmpty(eventArgs.selectOptions)) {
                            // get options value from all values in the current column
                            var colValues = jqGrid.colValues(colModel.name);
                            var optionsCount = colValues.length;
                            eventArgs.selectOptions = eventArgs.selectOptions || {};
                            for (var i = 0; i < optionsCount; i++) {
                                eventArgs.selectOptions.push({
                                    key: colValues[i],
                                    value: colValues[i]
                                });
                            }
                        }

                        var selectOptions = eventArgs.selectOptions;
                        var optionsCount = selectOptions.length;
                        var optionsValue = "";
                        for (var i = 0; i < optionsCount; i++) {
                            var selectOption = selectOptions[i];
                            optionsValue += selectOption.key + ':' + selectOption.value;
                            if (i < optionsCount - 1) {
                                optionsValue += ';';
                            }
                        }

                        //update  the colModel
                        colModel.editoptions = colModel.editoptions || {};
                        colModel.editoptions.value = optionsValue;
                        //save the key/value pairs collection on the colModel object directly (vpGrid extension)
                        colModel.selectKeyValues = eventArgs.selectOptions;


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function tryFindCurrentGridSchema() {
                    try {
                        var selector = "table[role=" + vpGrid.HtmlRoleAttribute.vpGridSchema + "]";
                        var jqElement = $(selector);

                        if (jqElement.found()) {
                            return jqElement;
                        }

                        vpGrid.logError({
                            message: "DOM element : <table role='" + vpGrid.HtmlRoleAttribute.vpGridSchema + "'> is missing. Please insert it in the Web page to activate the Excel grid."
                        });

                        return $(null);

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.initLocaleOptions = function () {
                    try {
                        if (isNullOrUndefinedOrEmpty(vpGridOptions)) {
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(vpGridOptions.jqGridOptions)) {
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(vpGridOptions.jqGridOptions.jgrid)) {
                            return;
                        }
                        var customOptions = vpGridOptions.jqGridOptions.jgrid;
                        if (isNullOrUndefinedOrEmpty(customOptions)) {
                            return;
                        }

                        try {
                            $.extend($.jgrid.formatter.date, customOptions.formatter.date);
                        } catch (e) {
                            vpGrid.logException(e);
                        }

                        try {
                            $.extend($.jgrid.formatter.currency, customOptions.formatter.currency);
                        } catch (e) {
                            vpGrid.logException(e);
                        }

                        try {
                            $.extend($.jgrid.formatter.integer, customOptions.formatter.integer);
                        } catch (e) {
                            vpGrid.logException(e);
                        }

                        try {
                            $.extend($.jgrid.formatter.number, customOptions.formatter.number);
                        } catch (e) {
                            vpGrid.logException(e);
                        }

                        try {
                            $.extend($.jgrid.formatter.checkbox, customOptions.formatter.checkbox);
                        } catch (e) {
                            vpGrid.logException(e);
                        }

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.initMinColdWidthOption = function () {
                    try {
                        if (isNullOrUndefinedOrEmpty(jqGrid.options.minColWidth)) {
                            vpGrid.logError({
                                functionName: "jqGrid.initMinColdWithOption",
                                message: "property minColWidth is not defined in jqGrid.options",
                                info: "minColdWitdth is assigned a default value of 20 pixels"
                            })
                            jqGrid.options.minColWidth = 20;
                        }

                        if (isNullOrUndefinedOrEmpty(vpGridOptions)) {
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(vpGridOptions.minColWidth)) {
                            return;
                        }

                        var widthValue = vpGridOptions.minColWidth;
                        if (isNotInt(widthValue)) {
                            vpGrid.logError({
                                functionName: "jqGrid.initMinColdWithOption",
                                message: "property minColWidth is not defined or has not the correct format in vpGrid Options",
                                info: "minColdWitdth is assigned a default value of " + jqGrid.options.minColWidth + " pixels"
                            })
                            return;
                        }

                        jqGrid.options.minColWidth = vpGridOptions.minColWidth;

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.initWidthOption = function () {
                    try {

                        if (isNullOrUndefinedOrEmpty(vpGridOptions)) {
                            return;
                        }

                        if (isNotBoolean(vpGridOptions.fitToBrowserWidth)) {
                            return;
                        }

                        if (vpGridOptions.fitToBrowserWidth) {
                            jqGrid.options.autowidth = true;
                            return;
                        }

                        jqGrid.options.autowidth = false;

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.initShrinkToFitOption = function () {
                    try {

                        if (isNullOrUndefinedOrEmpty(vpGridOptions)) {
                            return;
                        }

                        if (isNotBoolean(vpGridOptions.fixedColWidth)) {
                            return;
                        }

                        if (vpGridOptions.fixedColWidth) {
                            jqGrid.options.shrinkToFit = false;
                            return;
                        }

                        jqGrid.options.shrinkToFit = true;

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.initRowCheckboxOption = function () {
                    try {

                        if (isNullOrUndefinedOrEmpty(vpGridOptions)) {
                            return;
                        }

                        if (isNotBoolean(vpGridOptions.enableRowCheckbox)) {
                            return;
                        }

                        if (vpGridOptions.enableRowCheckbox === false) {
                            jqGrid.options.multiselect = false;
                            jqGrid.options.multiboxonly = false;
                            return;
                        }

                        jqGrid.options.multiselect = true;
                        jqGrid.options.multiboxonly = true;

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.initToolbarOption = function () {
                    try {

                        if (isNullOrUndefinedOrEmpty(vpGridOptions)) {
                            return;
                        }

                        if (isNotBoolean(vpGridOptions.enableCustomStatusBar)) {
                            return;
                        }

                        if (vpGridOptions.enableCustomStatusBar === false) {
                            jqGrid.options.toolbar = [false, ""];
                            return;
                        }

                        jqGrid.options.toolbar = [true, "bottom"];

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.initSummaryRowOption = function () {
                    try {

                        if (isNullOrUndefinedOrEmpty(vpGridOptions)) {
                            return;
                        }

                        if (isNotBoolean(vpGridOptions.enableSummaryRows)) {
                            return;
                        }

                        jqGrid.options.footerrow = false;
                        jqGrid.options.toprow = false;

                        if (vpGridOptions.enableSummaryRows) {
                            jqGrid.options.footerrow = true;
                        }

                        if (vpGridOptions.placeSummaryRowsOnTop) {
                            jqGrid.options.toprow = true;
                        }

                        jqGrid.options.numberOfSummaryRows = 1;
                        if (vpGridOptions.numberOfSummaryRows && vpGridOptions.numberOfSummaryRows > 1) {
                            jqGrid.options.numberOfSummaryRows = vpGridOptions.numberOfSummaryRows;
                        }

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.initOptions = function () {
                    try {
                        jqGrid.initLocaleOptions();
                        jqGrid.initMinColdWidthOption();
                        jqGrid.initWidthOption();
                        jqGrid.initShrinkToFitOption();
                        jqGrid.initToolbarOption();
                        jqGrid.initRowCheckboxOption();
                        jqGrid.initSummaryRowOption();
                        jqGrid.initAutoInsertNewLine();

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.host = function () {
                    try {
                        var jqGridHostSelector = "table[id=" + jqGrid.Id + "]";
                        var jqGridHost = $(jqGridHostSelector);

                        if (jqGridHost.notFound()) {
                            vpGrid.logError({
                                message: "DOM element : <table id='" + jqGrid.Id + "'> is missing. jqGrid cannot be managed by vpGrid."
                            });
                        }

                        return jqGridHost;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.container = function () {
                    try {
                        var selector = "div[role=" + vpGrid.HtmlRoleAttribute.vpGridBody + "]";
                        var jqGridContainer = $(selector);

                        if (jqGridContainer.notFound()) {
                            vpGrid.logError({
                                message: "Selector not found : '" + jqGridContainer.selector + "'",
                                functionName: "jqGrid.container",
                                info: "Dom element : <div role='" + vpGrid.HtmlRoleAttribute.vpGridBody + "'> is missing. Please insert it in the Web page to activate the Excel grid."

                            });
                        }

                        return jqGridContainer;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.body = function () {
                    try {

                        var jqGridContainer = jqGrid.container();
                        var bodySelector = "div.ui-jqgrid-bdiv";
                        var jqBody = jqGridContainer.find(bodySelector);

                        if (jqBody.notFound()) {
                            vpGrid.logError({
                                message: "Selector not found : '" + bodySelector + "'",
                                functionName: "jqGrid.body"
                            });
                            return $(null);
                        }

                        return jqBody;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.ribbonContainer = function () {
                    /// <signature>
                    /// <summary>Get the vpGrid  Ribbon container</summary>
                    /// <returns type="Object">Returns the ribbon container found by jQuery</returns>
                    /// </signature>
                    try {

                        var jqGridContainer = vpGrid.currentContainer();
                        var ribbonSelector = "div[role=" + vpGrid.HtmlRoleAttribute.vpGridRibbon + "]";
                        var jqRibbon = jqGridContainer.find(ribbonSelector);

                        if (jqRibbon.notFound()) {
                            vpGrid.logError({
                                message: "Selector not found : '" + ribbonSelector + "'",
                                functionName: "jqGrid.ribbonContainer"
                            });
                            return $(null);
                        }

                        return jqRibbon;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.summaryRowsContainer = function () {
                    try {

                        if (jqGrid.options.footerrow === false) {
                            // there is no summary row
                            return $(null);
                        }

                        var jqGridContainer = jqGrid.container();
                        var summaryRowSelector = "div.ui-jqgrid-sdiv";
                        var jqSummaryRow = jqGridContainer.find(summaryRowSelector);

                        if (jqSummaryRow.notFound()) {
                            vpGrid.logError({
                                message: "Selector not found : '" + summaryRowSelector + "'",
                                functionName: "jqGrid.summaryRowsContainer"
                            });
                            return $(null);
                        }

                        return jqSummaryRow;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.summaryRows = function () {
                    /// <signature>
                    /// <summary>Get all summary rows.</summary>
                    /// <returns type="Object">Returns a jQuery object that holds the summary rows collection</returns>
                    /// </signature>
                    try {
                        if (jqGrid.options.footerrow === false) {
                            // there is no summary row
                            return $(null);
                        }

                        var jqSummaryRowsContainer = jqGrid.summaryRowsContainer();

                        if (jqSummaryRowsContainer.notFound()) {
                            vpGrid.logError({
                                message: "Cannot find the summary rows container.",
                                functionName: "jqGrid.summaryRows"
                            });
                            return $(null);
                        }

                        var summaryRowSelector = "tr[role=row].footrow";
                        var jqSummaryRows = jqSummaryRowsContainer.find(summaryRowSelector);

                        if (jqSummaryRows.notFound()) {
                            vpGrid.logError({
                                functionName: "jqGrid.summaryRows",
                                message: "Summary Rows not found in DOM. Summary rows Selector='" + summaryRowSelector + "'"
                            });
                        }

                        return jqSummaryRows;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.summaryCell = function (uiIdentifier,cellName) {
                    /// <signature>
                    /// <summary>Get cell from specific summary row and specific column.</summary>
                    /// <param name="uiIdentifier" type="String">The value of the data tag 'data-vp-grid-ui-id'. This parameter should be set to empty if there is only one summary row.</param>
                    /// <param name="cellName" type="String">Name of the column where the summary cell is.</param>
                    /// <returns type="Object">Returns a jQuery object representing the found summary cell.</returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(uiIdentifier)) {
                            uiIdentifier = "";
                        }

                        if (isNotString(uiIdentifier)) {
                            vpGrid.logError({
                                functionName: "jqGrid.summaryCell",
                                message: "uiIdentifier is not valid string :'" + uiIdentifier + "'"
                            });
                            return;
                        }

                        var jqSummaryRow = jqGrid.summaryRow(uiIdentifier);
                        var cellSelector = "td[role=gridcell][aria-describedby=" + jqGrid.Id + "_" + cellName + "]";
                        var jqCell = jqSummaryRow.find(cellSelector);
                        if (jqCell.notFound()) {
                            vpGrid.logError({
                                message: "Summary Cell not found in DOM. Cell Selector='" + cellSelector + "'"
                            });
                        }

                        return jqCell;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.summaryRow = function (uiIdentifier) {
                    /// <signature>
                    /// <summary>Get the summary row with specified uiIdentifier.</summary>
                    /// <param name="uiIdentifier" type="String">The value of the data tag 'data-vp-grid-ui-id'. This parameter should be set to empty if there is only one summary row.</param>
                    /// <returns type="Object">Returns a jQuery object representing the found summary row.</returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(uiIdentifier)) {
                            uiIdentifier = "";
                        }

                        if (isNotString(uiIdentifier)) {
                            vpGrid.logError({
                                functionName: "jqGrid.summaryRow",
                                message: "uiIdentifier is not valid string :'" + uiIdentifier + "'"
                            });
                            return;
                        }

                        var jqSummaryRowsContainer = jqGrid.summaryRowsContainer();
                        var summaryRowSelector = "tr[role=row].footrow";
                        if (uiIdentifier.isNotNullOrEmptyOrWhitespace()) {
                            summaryRowSelector = "tr[role=row][data-vp-grid-ui-id=" + uiIdentifier + "].footrow";
                        }

                        var jqSummaryRow = jqSummaryRowsContainer.find(summaryRowSelector);
                        if (jqSummaryRow.notFound()) {
                            vpGrid.logError({
                                message: "Summary row not found in DOM. row Selector='" + summaryRowSelector + "'"
                            });
                        }

                        return jqSummaryRow;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.row = function (rowid) {
                    try {

                        if (isNullOrUndefinedOrEmpty(rowid)) {
                            vpGrid.logError({
                                functionName: "jqGrid.row",
                                message: "rowid is not valid id :'" + rowid + "'"
                            });
                            return $(null);
                        }

                        var jqGridHost = jqGrid.host();
                        var rowSelector = "tr[role=row][id=" + rowid + "]";
                        var jqRow = jqGridHost.find(rowSelector);

                        if (jqRow.notFound()) {
                            vpGrid.logError({
                                message: "jqGrid row not found in DOM. rowid='" + rowid + "'"
                            });
                        }
                        return jqRow;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.getRowThatHoldsItemWithKey = function (itemKey) {
                    /// <signature>
                    /// <summary>Get the jqGrid row that holds the item identified by its key itemKey.</summary>
                    /// <param name="itemKey" type="String">Key of the item to found in the grid</param>
                    /// <returns type="Object">jQuery object of the found table row</returns>
                    /// </signature>
                    try {

                        if (isNotString(itemKey)) {
                            vpGrid.logError({
                                functionName: "jqGrid.getRowThatHoldsItemWithKey",
                                message: "itemKey is not a valid string :'" + itemKey + "'"
                            });
                            return $(null);
                        }

                        //check if a key has been setup on the Key column
                        var keyColumnName = JQGrid.keyColumnName();
                        if (isNullOrUndefinedOrEmpty(keyColumnName)) {
                            vpGrid.logError({
                                functionName: "getRowThatHoldsItemWithKey",
                                message: "Key column not found.",
                                info: "Html data attribute '" + vpGrid.HtmlDataTag.ColumnType + "=key'," + " must be defined in the column schema."
                            });
                            return $(null);
                        }

                        var jqGridHost = jqGrid.host();
                        var itemsSelector = "td[role=gridcell][aria-describedby=" + jqGrid.Id + "_" + keyColumnName + "]";;
                        var jqItems = jqGridHost.find(itemsSelector);
                        var jqItemsCount = jqItems.length;
                        for (var i = 0; i < jqItemsCount; i++) {
                            var item = jqItems[i];
                            var jqItem = $(item);
                            var currentKey = jqItem.text();
                            if (itemKey === currentKey) {
                                var jqRow = jqItem.closest('tr[role = row]');
                                return jqRow;
                            }
                        }

                        vpGrid.logError({
                            functionName: "getRowThatHoldsItemWithKey",
                            message: "No row found from selector :'" + itemsSelector + "' with item key: '" + itemKey + "'"
                            
                        });

                        return $(null);

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.currrentRow = function () {
                    try {

                        var jqRow = jqGrid.row(jqGrid.currentRowId);
                         
                        if (jqRow.notFound()) {
                            vpGrid.logError({
                                functionName: "jqGrid.currrentRow",
                                message: "Current selected row cannot be found"
                            });
                            return $(null);
                        }

                        return jqRow;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.selectedRow = function () {
                    /// <signature>
                    /// <summary>Get the row from the first selected Item.
                    ///         A selected item is a row for which the first column checkbox has been checked.
                    ///         This function is not the same as jqGrid.currentRow.
                    ///             ->jqGrid.currentRow returns the row where a cell has been clicked either for edition or for any other process started on click event.
                    ///</summary>
                    /// <returns type="Object">Returns a jQuery object of the found table row</returns>
                    /// </signature>
                    try {
                        // get the jqGrid host table
                        var jqGridHost = jqGrid.host();

                        if (jqGridHost.notFound()) {
                            vpGrid.logError({
                                message: "Cannot get selected row because jqGrid host is not found."
                            });
                            return $(null);
                        }


                        var checkboxSelector = "input[type=checkbox][id=" + jqGrid.currentSelectedCheckboxId + "]";
                        var jqCheckbox = jqGridHost.find(checkboxSelector);

                        if (jqCheckbox.notFound()) {
                            //TODO : log
                            return $(null);
                        }


                        var jqRow = jqCheckbox.closest("tr[role=row]");

                        if (jqRow.notFound()) {
                            vpGrid.logError({
                                functionName: "jqGrid.selectedRow",
                                message: "Current selected row cannot be found."
                            });
                            return $(null);
                        }

                        return jqRow;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.cell = function (rowid, cellName) {
                    /// <signature>
                    /// <summary>Get the cell located in a specific row and in a specific column.</summary>
                    /// <param name="rowid" type="String">The id of the row (DOM id) where the cell is located</param>
                    /// <param name="cellname" type="String">Name of the column where the cell is located.</param>
                    /// <returns type="Object">Returns a jQuery object corresponding to the cell.</returns>
                    /// </signature>
                    try {
                        if (isNotString(cellName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.cell",
                                message: "cellName is not valid string :'" + cellName + "'"
                            });
                            return $(null);
                        }

                        var jqRow = jqGrid.row(rowid);
                        var cellSelector = "td[role=gridcell][aria-describedby=" + jqGrid.Id + "_" + cellName + "]";
                        var jqCell = jqRow.find(cellSelector);
                        if (jqCell.notFound()) {
                            vpGrid.logError({
                                functionName : "jqGrid.cell",
                                message: "Cell not found in DOM. Cell Selector='" + cellSelector + "', rowid='" + rowid +"'"
                            });
                        }

                        return jqCell;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.cellValue = function (rowid, cellName) {
                    /// <signature>
                    /// <summary>Get the value of the cell located in a specific row and in a specific column.</summary>
                    /// <param name="rowid" type="String">The id of the row (DOM id) where the cell is located</param>
                    /// <param name="cellname" type="String">Name of the column where the cell is located.</param>
                    /// <returns type="Object">Returns the value in native format.</returns>
                    /// </signature>
                    try {
                        if (isNotString(cellName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.cellValue",
                                message: "cellName is not valid string :'" + cellName + "'"
                            });
                            return $(null);
                        }

                        var jqGridHost = jqGrid.host();
                        var cellValue = jqGridHost.jqGrid('getCell', rowid, cellName);

                        return cellValue;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.inlineSummaryCell = function (rowid, cellName) {
                    try {
                        if (isNotString(cellName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.cell",
                                message: "cellName is not valid string :'" + cellName + "'"
                            });
                            return $(null);
                        }

                        var jqRow = jqGrid.row(rowid);
                        var cellSelector = "td[role=summarygridcell][aria-describedby=" + jqGrid.Id + "_" + cellName + "]";
                        var jqCell = jqRow.find(cellSelector);
                        if (jqCell.notFound()) {
                            vpGrid.logError({
                                message: "Cell not found in DOM. Cell Selector='" + cellSelector + "'"
                            });
                        }

                        return jqCell;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.cellValueIsInRange = function (rowid,cellName, cellValue, colModel) {
                    /// <signature>
                    /// <summary>Check if cell value is in the range defined by minValue and maxValue of the column schema.</summary>
                    /// <param name="rowid" type="String">HTML Id of the row where the cell is.</param>
                    /// <param name="cellName" type="String">Name of the column where the cell is.</param>
                    /// <param name="cellValue" type="String">Value of the cell being rendered by jqGrid</param>
                    /// <param name="colModel" type="Object">Column model of the cell</param>
                    /// <returns type="Boolean">Returns true if cell value is in range or if no range is defined.</returns>
                    /// </signature>
                    try {
                        if (isNotString(cellName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.cellValueIsInRange",
                                message: "cellName is not valid string :'" + cellName + "'"
                            });
                            return false;
                        }

                        if (colModel.isKey) {
                            return true;
                        }

                        if (colModel.isString) {
                            return true;
                        }

                        if (colModel.isDate) {
                            //TODO : implement Date range computation
                            return true;
                        }

                        if (colModel.isCheckbox) {
                            return true;
                        }

                        if (colModel.isNote) {
                            return true;
                        }

                        if (colModel.isLink) {
                            return true;
                        }

                        if (colModel.isImage) {
                            return true;
                        }

                        if (colModel.isAction) {
                            return true;
                        }

                        // now we are sure column is numeric
                        var editrules = colModel.editrules || {};
                        var minValue = editrules.minValue;
                        var maxValue = editrules.maxValue;
                        if (isInRange(cellValue, minValue, maxValue)) {
                            return true;
                        }

                        return false;
                        
                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                }

                jqGrid.cellValueIsOutOfRange = function (rowid,cellName, cellValue, colModel){
                    /// <signature>
                    /// <summary>Check if cell value is not in the range defined by minValue and maxValue of the column schema.</summary>
                    /// <param name="rowid" type="String">HTML Id of the row where the cell is.</param>
                    /// <param name="cellName" type="String">Name of the column where the cell is.</param>
                    /// <param name="cellValue" type="String">Value of the cell being rendered by jqGrid</param>
                    /// <param name="colModel" type="Object">Column model of the cell</param>
                    /// <returns type="Boolean">Returns true if cell value is not in range. Returns false if no range is defined in the column schema.</returns>
                    /// </signature>
                    return jqGrid.cellValueIsInRange(rowid,cellName, cellValue, colModel) === false;
                }

                jqGrid.setCell = function (rowid, cellName, cellValue) {
                    /// <signature>
                    /// <summary>Set the cell content with input value cellValue</summary>
                    /// <param name="rowid" type="String">The id of the row where the cell is located.</param>
                    /// <param name="cellname" type="String">Name of the cell to change. This name is defined in the colModel of the corresponding column.</param>
                    /// <param name="cellValue" type="String">Value to insert in cell.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNotString(cellName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.setCell",
                                message: "cellName is not valid string :'" + cellName + "'"
                            });
                            return ;
                        }

                        var jqGridHost = jqGrid.host();
                        
                        //TODO : raise event to gather CSS class and td attributes
                        jqGridHost.jqGrid("setCell", rowid, cellName, cellValue, false, false, true);


                    } catch (e) {
                        vpGrid.logException(e);
                        return;
                    }
                }

                jqGrid.setFooterData = function (uiIdentifier, userData, useCellFormatter) {
                    /// <signature>
                    /// <summary>Set summary row content with data from rowData</summary>
                    /// <param name="uiIdentifier" type="String">The value of the data tag 'data-vp-grid-ui-id'. This parameter should be set to empty if there is only one summary row.</param>
                    /// <param name="userData" type="Array">Literal object containing column values. Each property of this object must match a column name.</param>
                    /// <param name="useCellFormatter" type="Boolean">If set to true, the values are rendered using the formatters declared in the col schema columns.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(uiIdentifier)) {
                            uiIdentifier = "";
                        }

                        if (isNotString(uiIdentifier)) {
                            vpGrid.logError({
                                functionName: "jqGrid.setFooterData",
                                message: "uiIdentifier is not valid string :'" + uiIdentifier + "'"
                            });
                            return;
                        }

                        var jqGridHost = jqGrid.host();

                        if (uiIdentifier.isNullOrEmptyOrWhitespace()) {
                            jqGridHost.jqGrid("footerData", "set", userData, useCellFormatter);
                            return;
                        }
                        
                        jqGridHost.jqGrid("footerData2", "set", userData, useCellFormatter, uiIdentifier);

                    } catch (e) {
                        vpGrid.logException(e);
                        return;
                    }
                }

                jqGrid.contentArea = function () {
                    try {
                        var jqGridHost = jqGrid.host();

                        if (jqGridHost.notFound()) {
                            vpGrid.logError({
                                message: "Cannot get jqGrid contentArea because jqGrid host is not found."
                            });
                            return $(null);
                        }

                        var jqElement = jqGridHost.closest("div");

                        return jqElement;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.init = function () {
                    try {
                        jqGrid.isReady = false;

                        jqGrid.initData();

                        //find DOM element where to plug the jqGrid component
                        var jqGridSchema = tryFindCurrentGridSchema();
                        var jqGridRootNode = jqGridSchema.parent();

                        if (jqGridSchema.notFound()) {
                            //TODO : log
                            return;
                        }

                        //load jqGrid options
                        jqGrid.initOptions();

                        //Build the column models
                        buildColModels();

                        //Init the width of the grid (can be done only after buildColModels call
                        jqGrid.initWidth();

                        //Init the height of the grid (can be done only after buildColModels call
                        jqGrid.initHeight();

                        //Setup default Caption
                        if (vpGridOptions.defaultCaption) {
                            jqGrid.options.caption = vpGridOptions.defaultCaption;
                        }

                        //extract the custom grid caption schema
                        var customCaptionSelector = "[role=" + vpGrid.HtmlRoleAttribute.vpGridSchemaCaption + "]";
                        var customCaptionGrid = $(customCaptionSelector).detach();

                        //extract the custom grid status bar
                        var customStatusBarSelector = "[role=" + vpGrid.HtmlRoleAttribute.vpGridSchemaStatusBar + "]";
                        var customStatusBar = $(customStatusBarSelector).detach();

                        //extract the group headers description -> because they must be injected after calling jqGrid constructor
                        var groupHeadersSelector = "tr[role=" + vpGrid.HtmlRoleAttribute.vpGridSchemaColumnsGroup + "] ";
                        var customGroupHeaders = $(groupHeadersSelector).detach();

                        //detach the schema table from DOM
                        jqGridSchema.detach();

                        //dynamically add an empty table to host jqGrid in the DOM
                        var table = '<table id="' + jqGrid.Id + '"></table>';
                        var jqGridHost = $(table);
                        jqGridRootNode.append(jqGridHost);

                        //Create jqGrid
                        //TODO : raise event to enable listeners inspect and/or modify the jqGrid options
                        jqGridHost.jqGrid(jqGrid.options);

                        //inject custom Caption
                        if (customCaptionGrid.found() && vpGridOptions.enableCustomCaption) {
                            var jqGridCaptionSelector = "span.ui-jqgrid-title";
                            var jqGridCaption = $(jqGridCaptionSelector).first();
                            jqGridCaption.html("");
                            customCaptionGrid.appendTo(jqGridCaption);
                        }

                        //inject custom group headers
                        var groupHeadersOptions = buildGroupHeadersOptions(customGroupHeaders);
                        if (isNotNullOrUndefinedOrEmpty(groupHeadersOptions)) {
                            jqGridHost.jqGrid('setGroupHeaders', groupHeadersOptions);
                            // inject special css tag to be able to customize the rendering of the group headers
                            jqGridRootNode.find("tr[role=rowheader]").first().find("th[role=columnheader]").addClass('vp-grid-group-header');

                        }

                        //inject custom Status Bar
                        if (customStatusBar.found() && vpGridOptions.enableCustomStatusBar) {
                            //inject css class in bottom toolbar
                            var jqGridBottomToolbarSelector = "div[id=t_" + jqGrid.Id + "]";
                            var jqGridBottomToolbar = $(jqGridBottomToolbarSelector);
                            jqGridBottomToolbar.addClass('vp-grid-status-bar');
                            jqGridBottomToolbar.html("");
                            customStatusBar.appendTo(jqGridBottomToolbar);
                        }

                        //activate search filter toolbar on columns
                        if (vpGridOptions.enableFilterToolbar) {
                            var filterToolbarOptions = { stringResult: true, searchOnEnter: false, defaultSearch: 'cn', ignoreCase: true };
                            if (vpGridOptions.enableOperatorsInFilterToolbar) {
                                filterToolbarOptions.searchOperators = true;
                            }
                            jqGridHost.jqGrid('filterToolbar', filterToolbarOptions);
                            // inject special css tag to be able to customize the rendering of the filterToolbar
                            jqGridRootNode.find("table.ui-search-table").closest("th[role=columnheader]").addClass('vp-grid-filter-toolbar');
                        }

                        //activate frozen column --> does not work in this version
                        if (jqGrid.hasFrozenColumns) {
                            jqGridHost.jqGrid('setFrozenColumns');
                        }


                        //hide header checkbox if needed
                        if (vpGridOptions.enableMultiSelect === false) {
                            jqGrid.hideHeaderCheckbox();
                        }

                        //inject custom CSS in summary footer row container
                        if (vpGridOptions.enableSummaryRows) {
                            //inject css class in summary row
                            var jqSummaryRowsContainer = jqGrid.summaryRowsContainer();
                            jqSummaryRowsContainer.addClass('vp-grid-summary-rows');
                        }

                        if (vpGridOptions.enableSummaryRows) {
                            //add any additional summary rows if needed
                            jqGrid.createAdditionalSummaryRows();
                        }



                        //move summary rows on top if needed
                        jqGrid.placeSummaryRowsOnTop();

                        //TODO : bind qtip on column header if needed


                        //TODO : show welcome message window if needed


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.initData = function () {
                    try {

                        jqGrid.originalData = [];
                        jqGrid.updatedData = [];
                        jqGrid.deletedData = [];
                        jqGrid.insertedData = [];

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.initWidth = function () {
                    try {

                        if (jqGrid.hasFrozenColumns) {
                            jqGrid.options.shrinkToFit = false;
                        }

                        if (true) {

                        }

                        if (jqGrid.options.autowidth === true) {
                            return;
                        }

                        // sum all col width
                        var gridWidth = 0;
                        var colModels = jqGrid.options.colModel;
                        var colModelsCount = colModels.length;
                        for (var i = 0; i < colModelsCount; i++) {
                            var colModel = colModels[i];
                            gridWidth += colModel.width;
                        }

                        // left and right column
                        gridWidth += 50;

                        jqGrid.options.width = gridWidth;

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.initHeight = function () {
                    try {
                        if (isNullOrUndefinedOrEmpty(vpGridOptions)) {
                            return;
                        }

                        if (isNotNumber(vpGridOptions.numberOfVisibleRows)) {
                            return;
                        }

                        jqGrid.options.height = jqGrid.options.rowHeight * vpGridOptions.numberOfVisibleRows - 3;

                        if (vpGridOptions.enableSummaryRows) {
                            jqGrid.options.height += 3;
                        }


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.initAutoInsertNewLine = function () {
                    try {
                        if (isNullOrUndefinedOrEmpty(vpGridOptions)) {
                            return;
                        }

                        if (isNotBoolean(vpGridOptions.autoInsertNewLineAtBottom)) {
                            return;
                        }

                        jqGrid.options.autoInsertNewLineAtBottom = vpGridOptions.autoInsertNewLineAtBottom;


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.isValidColumnType = function (colType) {
                    try {
                        var validColTypes = ["string", "checkbox", "key", "currency", "date", "number", "year", "action", "note", "int", "link", "image", "actionValidator"];

                        if (isNotString(colType)) {
                            vpGrid.logError({
                                functionName: "jqGrid.isValidColumnType",
                                message: "Column type '" + colType + "' is not valid because it is not a string",
                                info: "Valid column types are :" + validColTypes.toString() + "."
                            });
                            return false;
                        }


                        if (colType.isInArray(validColTypes)) {
                            return true;
                        }

                        vpGrid.logError({
                            functionName: "jqGrid.isValidColumnType",
                            message: "Column type '" + colType + "' is not valid because it is unknown.",
                            info: "Valid column types are :" + validColTypes.toString() + "."
                        });
                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                }

                jqGrid.isNotValidColumnType = function (colType) {
                    return jqGrid.isValidColumnType(colType) === false;
                }

                jqGrid.isValidColumnName = function (colName) {
                    try {
                        if (isNotString(colName)) {
                            return false;
                        }

                        if (colName === "cb" && jqGrid.options.multiselect) {
                            vpGrid.logError({
                                message: "'cb' is a reserved name for a column when row checkbox is enabled."
                            });
                            return false;
                        }

                        if (colName === "subgrid") {
                            vpGrid.logError({
                                message: "'subgrid' is a reserved name for a column."
                            });
                            return false;
                        }

                        if (colName === "rn") {
                            vpGrid.logError({
                                message: "'rn' is a reserved name for a column."
                            });
                            return false;
                        }

                        return true;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                }

                jqGrid.isNotValidColumnName = function (colName) {
                    return jqGrid.isValidColumnName(colName) === false;
                }

                jqGrid.insertNewRow = function (dataRow, pos) {
                    /// <signature>
                    /// <summary>Insert a new row in the grid</summary>
                    /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
                    /// <param name="pos" type="String">Position of insertion. Valid values are : 'last' and 'first'</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        if (isNullOrUndefined(dataRow)) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertNewRow",
                                message: "dataRow object is null or undefined."
                            });
                            return;
                        }

                        if (isNotString(pos)) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertNewRow",
                                message: "Position parameter is not valid. Its value is :'" + pos + "'."
                            });
                            return;
                        }

                        var allowedValues = ['first', 'last'];
                        if (pos.isNotInArray(allowedValues)) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertNewRow",
                                message: "Position parameter is not valid. Its value is :'" + pos + "'.",
                                info: "Valid values are : " + allowedValues.toString()
                            });
                            return;
                        }

                        var jqGridHost = jqGrid.host();
                        var inserted = jqGridHost.jqGrid('addRowData', undefined, dataRow, pos);

                        if (inserted === false) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertNewRow",
                                message: "Row cannot be inserted by jqGrid"
                            });

                            return;
                        }

                        jqGrid.totalItemCount += 1;
                        //set number of rows in jqGrid
                        var gridOptions = {
                            rowNum: jqGrid.totalItemCount
                        };
                        jqGridHost.jqGrid('setGridParam', gridOptions);

                        //TODO : refresh the grid with current filters

                        //TODO : update the inserted data array
                        jqGrid.insertedData.push(dataRow);
                        jqGrid.insertDataOnRemote();

                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.insertDataOnRemote = function () {
                    try {

                        if (isNullOrUndefinedOrEmpty(jqGrid.insertedData)) {
                            // there is nothing to do
                            return;
                        }

                        var dataRow = jqGrid.insertedData[0];
                        jqGrid.insertDataOnRemoteWith(dataRow);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.updateDataOnRemote = function () {
                    try {

                        if (isNullOrUndefinedOrEmpty(jqGrid.updatedData)) {
                            // there is nothing to do
                            return;
                        }

                        var dataRow = jqGrid.updatedData[0];
                        jqGrid.updateDataOnRemoteWith(dataRow);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.deleteDataOnRemote = function () {
                    try {

                        if (isNullOrUndefinedOrEmpty(jqGrid.deletedData)) {
                            // there is nothing to do
                            return;
                        }

                        var dataRow = jqGrid.deletedData[0];
                        jqGrid.deleteDataOnRemoteWith(dataRow);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.insertDataOnRemoteWith = function (dataRow) {
                    /// <signature>
                    /// <summary>Trigger an ajax operation to send input data for insertion in remote database.</summary>
                    /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        //step 0 : show qTip2 dialog
                        //showLoadingMessage();

                        if (isNullOrUndefinedOrEmpty(dataRow)) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertDataOnRemoteWith",
                                message: "Input data is null or empty : '" + dataRow + "'"
                            });
                            return;
                        }

                        var ajaxOptions = {
                            cache: false,
                            type: "GET",
                            dataType: "json",
                            success: function (response) {
                                try {
                                    jqGrid.loadInsertedDataFromWebResponse(response, dataRow);
                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                            },
                            complete: function (xhr, textStatus) {
                                try {
                                    //TODO : remove the qtip2 message
                                    //jqGrid.loadDataComplete(xhr, textStatus);

                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                                finally {
                                    // continue remote operations
                                    jqGrid.insertDataOnRemote();
                                }
                            }
                        };

                        //get url to be requested
                        var crudOperations = vpGridOptions.crudOptions;
                        if (isNullOrUndefinedOrEmpty(crudOperations)) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertDataOnRemoteWith",
                                message: "CRUD operations are not defined in the vpGrid Options object. Data cannot be sent to server."
                            });
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(crudOperations.insert)) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertDataOnRemoteWith",
                                message: "CRUD operation Insert is not defined in the vpGrid Options object. Data cannot be sent to server."
                            });
                            return;
                        }

                        var requestUrl = crudOperations.insert;
                        ajaxOptions.url = requestUrl;

                        ajaxOptions.data = dataRow;

                        $.extend(ajaxOptions, vpGridAjaxOptions);

                        //TODO : raise event to enable listeners inspect and/or modify ajaxOptions

                        $.ajax(ajaxOptions);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.updateDataOnRemoteWith = function (dataRow) {
                    /// <signature>
                    /// <summary>Trigger an ajax operation to send input data for update in remote database.</summary>
                    /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        //step 0 : show qTip2 dialog
                        //showLoadingMessage();

                        if (isNullOrUndefinedOrEmpty(dataRow)) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateDataOnRemoteWith",
                                message: "Input data is null or empty : '" + dataRow + "'"
                            });
                            return;
                        }

                        var ajaxOptions = {
                            cache: false,
                            type: "GET",
                            dataType: "json",
                            success: function (response) {
                                try {
                                    jqGrid.loadUpdatedDataFromWebResponse(response, dataRow);
                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                            },
                            complete: function (xhr, textStatus) {
                                try {
                                    //TODO : remove the qtip2 message
                                    //jqGrid.loadDataComplete(xhr, textStatus);

                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                                finally {
                                    // continue remote operations
                                    jqGrid.updateDataOnRemote();
                                }
                            }
                        };

                        //get url to be requested
                        var crudOperations = vpGridOptions.crudOptions;
                        if (isNullOrUndefinedOrEmpty(crudOperations)) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateDataOnRemoteWith",
                                message: "CRUD operations are not defined in the vpGrid Options object. Data cannot be sent to server."
                            });
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(crudOperations.update)) {
                            vpGrid.logError({
                                functionName: "jqGrid.updateDataOnRemoteWith",
                                message: "CRUD operation Update is not defined in the vpGrid Options object. Data cannot be sent to server."
                            });
                            return;
                        }

                        var requestUrl = crudOperations.update;

                        //check for custom crud url
                        if (dataRow.crudKey) {
                            var propertyName = dataRow.crudKey;

                            if (isNullOrUndefinedOrEmpty(crudOperations[propertyName])) {
                                vpGrid.logError({
                                    functionName: "jqGrid.updateDataOnRemoteWith",
                                    message: "CRUD operation Update with key : '" + dataRow.crudKey + "' is not defined in the vpGrid Options object. Data cannot be sent to server."
                                });
                                return;
                            }
                            var customUrl = crudOperations[propertyName];
                            requestUrl = customUrl;
                        }

                        ajaxOptions.url = requestUrl;

                        ajaxOptions.data = dataRow;

                        $.extend(ajaxOptions, vpGridAjaxOptions);

                        //TODO : raise event to enable listeners inspect and/or modify ajaxOptions

                        $.ajax(ajaxOptions);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.deleteDataOnRemoteWith = function (dataRow) {
                    /// <signature>
                    /// <summary>Trigger an ajax operation to send input data for update in remote database.</summary>
                    /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        //step 0 : show qTip2 dialog
                        //showLoadingMessage();

                        if (isNullOrUndefinedOrEmpty(dataRow)) {
                            vpGrid.logError({
                                functionName: "jqGrid.deleteDataOnRemoteWith",
                                message: "Input data is null or empty : '" + dataRow + "'"
                            });
                            return;
                        }

                        var ajaxOptions = {
                            cache: false,
                            type: "GET",
                            dataType: "json",
                            success: function (response) {
                                try {
                                    jqGrid.loadDeletedDataFromWebResponse(response, dataRow);
                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                            },
                            complete: function (xhr, textStatus) {
                                try {
                                    //TODO : remove the qtip2 message
                                    //jqGrid.loadDataComplete(xhr, textStatus);

                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                                finally {
                                    // continue remote operations
                                    jqGrid.deleteDataOnRemote();
                                }
                            }
                        };

                        //get url to be requested
                        var crudOperations = vpGridOptions.crudOptions;
                        if (isNullOrUndefinedOrEmpty(crudOperations)) {
                            vpGrid.logError({
                                functionName: "jqGrid.deleteDataOnRemoteWith",
                                message: "CRUD operations are not defined in the vpGrid Options object. Data cannot be sent to server."
                            });
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(crudOperations['delete'])) {
                            vpGrid.logError({
                                functionName: "jqGrid.deleteDataOnRemoteWith",
                                message: "CRUD operation Delete is not defined in the vpGrid Options object. Data cannot be sent to server."
                            });
                            return;
                        }

                        var requestUrl = crudOperations['delete'];
                        ajaxOptions.url = requestUrl;

                        ajaxOptions.data = dataRow;

                        $.extend(ajaxOptions, vpGridAjaxOptions);

                        //TODO : raise event to enable listeners inspect and/or modify ajaxOptions

                        $.ajax(ajaxOptions);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.loadInsertedDataFromWebResponse = function (response, dataRow) {
                    /// <signature>
                    /// <summary>Process response data after insertion on remote server.
                    ///             The response object must have the following structure:
                    ///             {
                    ///                 "done" : true|false,
                    ///                 "errorMessage" : "",
                    ///                 "data": 
                    ///                 {"remoteId" : "xxx"}
                    ///               -> remoteId = Name of the key column
                    ///               -> xxx = primary key set by remote server after inserting the data
                    ///             }
                    /// </summary>
                    /// <param name="response" type="Object">Literal object sent by remote server.</param>
                    /// <param name="dataRow" type="Object">Original data sent to server.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(response)) {
                            vpGrid.logError({
                                functionName: "jqGrid.loadInsertedDataFromWebResponse",
                                message: "Server response is null or undefined.",
                                info: "Check if the server is up and running. Check also if the crud options are correctly configured when calling vpGrid.init function."
                            });
                            return;
                        }

                        //TODO : raise event so that listeners can inspect and/or modify response object

                        if (response.done === false) {
                            vpGrid.logError({
                                functionName: "jqGrid.loadInsertedDataFromWebResponse",
                                message: "An error has occured on server : " + response.errorMessage
                            });
                            jqGrid.showUINotification("", response.errorMessage, true);
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(response.data)) {
                            vpGrid.logError({
                                functionName: "jqGrid.loadInsertedDataFromWebResponse",
                                message: "response.data object is null or undefined or empty.",
                                info: "response.data is forced to be an empty literal object."
                            });
                            response.data = {};
                        }

                        //raise event so that listeners can inspect and/or modify response data

                        var receivedData = response.data;
                        var keyColumnName = jqGrid.keyColumnName();
                        var newRowId = receivedData[keyColumnName];
                        var currentRowId = dataRow[keyColumnName];
                        jqGrid.setCell(currentRowId, keyColumnName, newRowId);


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                    finally {
                        var insertedDataRow = jqGrid.insertedData.shift();
                    }
                }

                jqGrid.loadUpdatedDataFromWebResponse = function (response, dataRow) {
                    /// <signature>
                    /// <summary>Process response data after update operation on remote server.
                    ///             The response object must have the following structure:
                    ///             {
                    ///                 "done" : true|false,
                    ///                 "errorMessage" : "",
                    ///                 "data": 
                    ///                 {"remoteId" : "xxx"}
                    ///               -> remoteId = Name of the key column
                    ///               
                    ///             }
                    /// </summary>
                    /// <param name="response" type="Object">Literal object sent by remote server after its update operation on dataRow.</param>
                    /// <param name="dataRow" type="Object">Original data sent to server.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(response)) {
                            vpGrid.logError({
                                functionName: "jqGrid.loadUpdatedDataFromWebResponse",
                                message: "Server response is null or undefined.",
                                info: "Check if the server is up and running. Check also if the crud options are correctly configured when calling vpGrid.init function."
                            });
                            return;
                        }

                        //TODO : raise event so that listeners can inspect and/or modify response object

                        if (response.done === false) {
                            vpGrid.logError({
                                functionName: "jqGrid.loadUpdatedDataFromWebResponse",
                                message: "An eror has occured on server : " + response.message
                            });
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(response.data)) {
                            vpGrid.logError({
                                functionName: "jqGrid.loadUpdatedDataFromWebResponse",
                                message: "response.data object is null or undefined or empty.",
                                info: "response.data is forced to be an empty literal object."
                            });
                            response.data = {};
                        }

                        //raise event so that listeners can inspect and/or modify response data

                        var receivedData = response.data;
                        var keyColumnName = jqGrid.keyColumnName();
                        var currentRowId = dataRow[keyColumnName];

                        //TODO : update any cell if needed
                        //jqGrid.setCell(currentRowId, keyColumnName, newRowId);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                    finally {
                        var updatedDataRow = jqGrid.updatedData.shift();
                    }
                }

                jqGrid.loadDeletedDataFromWebResponse = function (response, dataRow) {
                    /// <signature>
                    /// <summary>Process response data after Delete operation on remote server.
                    ///             The response object must have the following structure:
                    ///             {
                    ///                 "done" : true|false,
                    ///                 "errorMessage" : "",
                    ///                 "data": 
                    ///                 {"remoteId" : "xxx"}
                    ///               -> remoteId = Name of the key column
                    ///               -> primary key of the deleted row on server
                    ///               
                    ///             }
                    /// </summary>
                    /// <param name="response" type="Object">Literal object sent by remote server after its update operation on dataRow.</param>
                    /// <param name="dataRow" type="Object">Original data sent to server.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {
                        if (isNullOrUndefinedOrEmpty(response)) {
                            vpGrid.logError({
                                functionName: "jqGrid.loadDeletedDataFromWebResponse",
                                message: "Server response is null or undefined.",
                                info: "Check if the server is up and running. Check also if the crud options are correctly configured when calling vpGrid.init function."
                            });
                            return;
                        }

                        //TODO : raise event so that listeners can inspect and/or modify response object

                        if (response.done === false) {
                            vpGrid.logError({
                                functionName: "jqGrid.loadDeletedDataFromWebResponse",
                                message: "An error has occured on server : " + response.message
                            });
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(response.data)) {
                            vpGrid.logError({
                                functionName: "jqGrid.loadDeletedDataFromWebResponse",
                                message: "response.data object is null or undefined or empty.",
                                info: "response.data is forced to be an empty literal object."
                            });
                            response.data = {};
                        }

                        //raise event so that listeners can inspect and/or modify response data

                        var receivedData = response.data;
                        var keyColumnName = jqGrid.keyColumnName();
                        var currentRowId = dataRow[keyColumnName];

                        //TODO : update any cell if needed
                        //jqGrid.setCell(currentRowId, keyColumnName, newRowId);

                        

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                    finally {
                        var deletedDataRow = jqGrid.deletedData.shift();
                    }
                }

                jqGrid.hasRemoteOperationPending = function() {
                    try {
                        if (jqGrid.insertedData.length > 0) {
                            return true;
                        }

                        if (jqGrid.updatedData.length > 0) {
                            return true;
                        }

                        if (jqGrid.deletedData.length > 0) {
                            return true;
                        }

                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                }

                jqGrid.hasNoRemoteOperationPending = function () {
                    return jqGrid.hasRemoteOperationPending() === false;
                }

                jqGrid.onBeforeUnload = function (event) {
                    /// <signature>
                    /// <summary>Event handler that prevents closing window if a remote operation is pending.</summary>
                    /// <param name="event" type="Object">Literal object passed by the window.onbeforeunload event</param>
                    /// <returns type="String">Returns a non empty message if CRUD operations are not completed.</returns>
                    /// </signature>
                    try {
                        if (jqGrid.hasNoRemoteOperationPending()) {
                            return ;
                        }

                        var message = vpGrid.UIString.pendingOperationOnRemoteServer;
                        return message;
                        
                    } catch (e) {
                        vpGrid.logException(e);
                        return ;
                    }
                }

                jqGrid.insertNewRowAfterSelected = function (dataRow) {
                    /// <signature>
                    /// <summary>Insert a new row in the grid after the currently selected row.</summary>
                    /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        if (isNullOrUndefined(dataRow)) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertNewRowAfterSelected",
                                message: "dataRow object is null or undefined."
                            });
                            return;
                        }

                        var jqGridHost = jqGrid.host();
                        var inserted = jqGridHost.jqGrid('addRowData', undefined, dataRow, 'after', jqGrid.currentRowId);

                        if (inserted === false) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertNewRowAfterSelected",
                                message: "Row cannot be inserted by jqGrid"
                            });

                            return;
                        }

                        jqGrid.totalItemCount += 1;
                        //set number of rows in jqGrid
                        var gridOptions = {
                            rowNum: jqGrid.totalItemCount
                        };
                        jqGridHost.jqGrid('setGridParam', gridOptions);


                        //TODO : refresh the grid with current filters

                        //TODO : update the inserted data array

                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.insertInlineSummaryRowAfterSelected = function (dataRow) {
                    /// <signature>
                    /// <summary>Insert a new summary row in the grid after the currently selected row.</summary>
                    /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        if (isNullOrUndefined(dataRow)) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertInlineSummaryRowAfterSelected",
                                message: "dataRow object is null or undefined."
                            });
                            return;
                        }

                        var jqGridHost = jqGrid.host();
                        var rowid = 'summaryAfter' + jqGrid.currentRowId;
                        var inserted = jqGridHost.jqGrid('addInlineSummaryRowData', rowid, dataRow, 'after', jqGrid.currentRowId);

                        if (inserted === false) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertInlineSummaryRowAfterSelected",
                                message: "Row cannot be inserted by jqGrid"
                            });

                            return;
                        }


                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.insertInlineSummaryRowAfter = function (rowid, dataRow, summaryRowidPrefix) {
                    /// <signature>
                    /// <summary>Insert a new summary row in the grid after the row with id rowid.</summary>
                    /// <param name="rowid" type="String">Dom id of the row after which to insert the summary row.</param>
                    /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
                    /// <param name="summaryRowidPrefix" type="String">Prefix that will be used to build the Dom id of the summary row that will be created. 
                    ///             If not defined this parameter will receive the value : 'summaryAfter'
                    ///             The Dom id of the summary row will have the value : summaryRowidPrefix + rowid
                    ///             The data attribute "data-vp-grid-summary-id" will be automatically injected on the summary row :
                    ///                     data-vp-grid-summary-id=summaryRowidPrefix
                    ///                     -> this will be possible to create a summary row in the footer that is the sum of only summary rows with that data tag value
                    /// </param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        if (isNullOrUndefined(dataRow)) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertInlineSummaryRowAfter",
                                message: "dataRow object is null or undefined."
                            });
                            return;
                        }

                        var summaryRowid = 'summaryAfter' + rowid;

                        if (isNotNullOrUndefinedOrEmpty(summaryRowidPrefix)) {
                            summaryRowid = summaryRowidPrefix  + rowid;
                        }

                        var jqGridHost = jqGrid.host();
                        var inserted = jqGridHost.jqGrid('addInlineSummaryRowData', summaryRowid, dataRow, 'after', rowid);

                        if (inserted === false) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertInlineSummaryRowAfter",
                                message: "Row cannot be inserted by jqGrid"
                            });

                            return;
                        }

                        //flag rowid as having a summary row after itself
                        jqGrid.row(rowid).addClass('has-summary-row-after');

                        // add the data-tag 
                        jqGrid.row(summaryRowid).attr('data-vp-grid-summary-id', summaryRowidPrefix);

                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.updateInlineSummaryRowAfter = function (rowid, dataRow, summaryRowidPrefix) {
                    /// <signature>
                    /// <summary>Update an existing inline summary row in the grid after the row with id rowid.</summary>
                    /// <param name="rowid" type="String">Dom id of the row after which to insert the summary row.</param>
                    /// <param name="dataRow" type="Object">Literal object containing column values to show in the summary row. Each property of this object must match a column name.</param>
                    /// <param name="summaryRowidPrefix" type="String">Prefix that will be used to build the Dom id of the summary row that will be updated. 
                    ///             If not defined this parameter will receive the value : 'summaryAfter'
                    ///             The Dom id of the summary row will have the value : summaryRowidPrefix + rowid
                    ///             The data attribute "data-vp-grid-summary-id" will be automatically injected on the summary row :
                    ///                     data-vp-grid-summary-id=summaryRowidPrefix
                    ///                     -> this will be possible to create a summary row in the footer that is the sum of only summary rows with that data tag value
                    /// </param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        if (isNullOrUndefined(dataRow)) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertInlineSummaryRowAfter",
                                message: "dataRow object is null or undefined."
                            });
                            return;
                        }

                        var summaryRowid = 'summaryAfter' + rowid;

                        if (isNotNullOrUndefinedOrEmpty(summaryRowidPrefix)) {
                            summaryRowid = summaryRowidPrefix + rowid;
                        }

                        var jqGridHost = jqGrid.host();
                        var updated = jqGridHost.jqGrid('setInlineSummaryRowData', summaryRowid, dataRow);

                        if (updated === false) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertInlineSummaryRowAfter",
                                message: "Row cannot be inserted by jqGrid"
                            });

                            return;
                        }

                        //check if cell content is out of range
                        jqGrid.options.afterUpdateInlineSummaryRow(rowid, summaryRowid, dataRow)
                        

                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.insertInlineSummaryRowBefore = function (rowid, dataRow, summaryRowidPrefix) {
                    /// <signature>
                    /// <summary>Insert a new summary row in the grid before the row with id rowid.</summary>
                    /// <param name="rowid" type="String">Dom id of the row before which to insert the summary row.</param>
                    /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
                    /// <param name="summaryRowidPrefix" type="String">Prefix that will be used to build the Dom id of the summary row that will be created. 
                    ///             If not defined this parameter will receive the value : 'summaryBefore'
                    ///             The Dom id of the summary row will have the value : summaryRowidPrefix + rowid
                    ///             The data attribute "data-vp-grid-summary-id" will be automatically injected on the summary row :
                    ///                     data-vp-grid-summary-id=summaryRowidPrefix
                    ///                     -> this will be possible to create a summary row in the footer that is the sum of only summary rows with that data tag value
                    /// </param>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        if (isNullOrUndefined(dataRow)) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertInlineSummaryRowBefore",
                                message: "dataRow object is null or undefined."
                            });
                            return;
                        }

                       
                        var summaryRowid = 'summaryBefore' + rowid;
                        if (isNotNullOrUndefinedOrEmpty(summaryRowidPrefix)) {
                            summaryRowid = summaryRowidPrefix + rowid;
                        }

                        var jqGridHost = jqGrid.host();
                        var inserted = jqGridHost.jqGrid('addInlineSummaryRowData', summaryRowid, dataRow, 'before', rowid);

                        if (inserted === false) {
                            vpGrid.logError({
                                functionName: "jqGrid.insertInlineSummaryRowBefore",
                                message: "Row cannot be inserted by jqGrid"
                            });

                            return;
                        }

                        //flag rowid as having a summary row after itself
                        jqGrid.row(summaryRowid).addClass('is-summary-row-before');

                        // add the data-tag 
                        jqGrid.row(summaryRowid).attr('data-vp-grid-summary-id', summaryRowidPrefix);


                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                jqGrid.deleteCurrentRow = function () {
                    /// <signature>
                    /// <summary>Delete the current selected row in the grid</summary>
                    /// <returns type="void"></returns>
                    /// </signature>
                    try {

                        var rowid = jqGrid.currentRowId;
                        if (isNullOrUndefinedOrEmpty(rowid)) {
                            vpGrid.logError({
                                functionName: "jqGrid.deleteCurrentRow",
                                message: "Current Row cannot be removed because its DOM id is not valid: '" + rowid + "'"
                            });
                        }

                        var rowData = jqGrid.rowData(rowid);

                        var jqGridHost = jqGrid.host();
                        var deleted = jqGridHost.jqGrid('delRowData', rowid);

                        if (deleted === false) {
                            vpGrid.logError({
                                functionName: "jqGrid.deleteCurrentRow",
                                message: "Current Row cannot be removed by jqGrid"
                            });

                            return;
                        }

                        //reset the current selected row
                        jqGrid.currentRowId = null;
                        jqGrid.lastSelectedCheckboxId = "";
                        jqGrid.currentSelectedCheckboxId = "";

                        // update number of rows in the grid
                        jqGrid.totalItemCount -= 1;
                        //set number of rows in jqGrid
                        var gridOptions = {
                            rowNum: jqGrid.totalItemCount
                        };
                        jqGridHost.jqGrid('setGridParam', gridOptions);


                        //TODO : refresh the grid with current filters

                        //TODO : update the deleted data array
                        jqGrid.deletedData.push(rowData);
                        jqGrid.deleteDataOnRemote();

                    } catch (e) {
                        vpGrid.logException(e);

                    }
                }

                function buildColModels() {
                    try {
                        var jqGridSchema = tryFindCurrentGridSchema();

                        if (jqGridSchema.notFound()) {
                            //TODO : log
                            return;
                        }

                        var columsSelector = "tr[role=" + vpGrid.HtmlRoleAttribute.vpGridSchemaColumns + "] ";
                        columsSelector += "th";
                        var jqColumns = jqGridSchema.find(columsSelector);

                        if (jqColumns.notFound()) {
                            vpGrid.logError({
                                message: "Missing description of the excell grid columns. Please insert them in the Web page to activate the Excel grid."
                            });
                        }

                        var colNames = [];
                        var colModel = [];
                        
                        var columnsCount = jqColumns.length;
                        for (var i = 0; i < columnsCount; i++) {
                            var jqColumn = $(jqColumns[i]);
                            var colSchema = {};
                            // get the column title
                            colSchema.title = jqColumn.html();

                            //get the column name
                            colSchema.name = jqColumn.attr(vpGrid.HtmlDataTag.ColumnName);
                            colSchema.index = colSchema.name;
                            if (jqGrid.isNotValidColumnName(colSchema.name)) {
                                vpGrid.logError({
                                    message: "Column name is not valid.",
                                    info: "You must give another name for the column : '" + outerHtml(jqColumn[0]) + "'"
                                });
                            }


                            //get the column width
                            var minColWidth = jqGrid.options.minColWidth;
                            colSchema.width = jqColumn.toIntOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnWidth, minColWidth)
                            colSchema.fixed = jqColumn.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnFixedWidth, false)

                            //enforce column min width
                            if (colSchema.width < minColWidth && colSchema.fixed === false) {
                                colSchema.width = minColWidth;
                            }

                            //get the column hidden attribute
                            colSchema.hidden = jqColumn.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnHidden, false);


                            //get the column frozen attribute
                            colSchema.frozen = jqColumn.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnFrozen, false);
                            if (colSchema.frozen) {
                                jqGrid.hasFrozenColumns = true;
                            }

                            //get the column sortable attribute
                            colSchema.sortable = jqColumn.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnSortable, true);


                            //get the column editable attribute
                            colSchema.editable = jqColumn.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnEditable, false);

                            //get the column edittype attribute
                            // warning : edittype may be overwritten below on specific column Type
                            colSchema.edittype = jqColumn.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnEditType, "text");
                            if (colSchema.edittype === "select") {
                                // create a custom property to flag this column as a select type
                                // this flag will be used to dynamically inject select options in cell editing
                                colSchema.isSelect = true;
                            }

                            if (colSchema.edittype === "autocomplete") {
                                // create a custom property to flag this column as an input textbox with autocomplete
                                // this flag will be used to dynamically inject autocomplete plug-in in cell editing
                                colSchema.edittype = "text";
                                colSchema.isAutocomplete = true;
                            }

                            //setup default search options on columns (used by filterToolbar)
                            colSchema.stype = 'text';
                            colSchema.searchoptions = { sopt: ['cn', 'eq', 'bw', 'bn', 'nc', 'ew', 'en'] };

                            

                            //get the column align attribute
                            colSchema.align = jqColumn.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnAlign, "left");

                            //get the column type attribute
                            var colType = jqColumn.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnType, "string");

                            if (jqGrid.isNotValidColumnType(colType)) {
                                vpGrid.logError({
                                    message: "Column type '" + colType + "' is not valid.",
                                    info: "You must give another type for the column : '" + outerHtml(jqColumn[0]) + "'"
                                });
                            }
                            if (colType === "string") {
                                colSchema.isString = true;
                            }

                            if (colType === "checkbox") {
                                colSchema.formatter = "checkbox";
                                colSchema.edittype = "checkbox";
                                // create a custom property to flag this column as checkbox type
                                // this flag will be used to dynamically inject xxx in cell editing
                                colSchema.isCheckbox = true;
                            }

                            if (colType === "note") {
                                colSchema.edittype = "textarea";
                                colSchema.editoptions = { rows: "2", cols: "15" };
                                // create a custom property to flag this column as note type
                                // this flag will be used to dynamically inject xxx in cell editing
                                colSchema.isNote = true;
                            }

                            if (colType === "currency") {
                                colSchema.formatter = "currency";
                                colSchema.formatoptions = jqGrid.defaultCurrencyFormatOptions();

                                colSchema.isCurrency = true;
                                colSchema.editrules = {
                                    number: true,
                                    minValue: jqColumn.toIntOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnMinValue, null),
                                    maxValue: jqColumn.toIntOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnMaxValue, null)
                                };
                            }

                            if (colType === "int") {
                                colSchema.formatter = "integer";

                                colSchema.isInteger = true;
                                colSchema.editrules = {
                                    integer: true,
                                    minValue: jqColumn.toIntOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnMinValue, null),
                                    maxValue: jqColumn.toIntOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnMaxValue, null)
                                };
                            }

                            if (colType === "number") {
                                colSchema.formatter = "number";
                                colSchema.formatoptions = jqGrid.defaultNumberFormatOptions();

                                colSchema.isNumber = true;
                                colSchema.editrules = {
                                    number: true,
                                    minValue: jqColumn.toIntOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnMinValue, null),
                                    maxValue: jqColumn.toIntOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnMaxValue, null)
                                };
                            }

                            if (colType === "link") {
                                colSchema.formatter = jqGrid.linkFormatter;
                                colSchema.unformat = jqGrid.linkUnFormatter;
                                colSchema.formatoptions = { target: '_vpTab' };
                                colSchema.isLink = true;
                            }

                            if (colType === "date") {
                                colSchema.formatter = "date";
                                colSchema.sorttype = "date";
                                // create a custom property to flag this column as date type
                                // this flag will be used to dynamically inject datepicker in cell editing
                                colSchema.isDate = true;
                            }

                            if (colType === "year") {
                                // create a custom property to flag this column as date type
                                // this flag will be used to dynamically inject select element in cell editing
                                colSchema.isYear = true;
                                colSchema.editrules = {
                                    integer: true,
                                    minValue: jqColumn.toIntOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnMinValue, null),
                                    maxValue: jqColumn.toIntOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnMaxValue, null)
                                };
                            }

                            if (colType === "image") {
                                colSchema.formatter = jqGrid.imageFormatter;
                                colSchema.unformat = jqGrid.imageUnformatter;
                                colSchema.isImage = true;
                            }

                            if (colType === "key") {
                                colSchema.isKey = true;
                                colSchema.key = true; // jqGrid generates its own id for each table row
                            }

                            var actionType = jqColumn.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnActionType, "");
                            if (colType === "action") {
                                //fix the width of the action
                                colSchema.fixed = true;
                                colSchema.search = false;
                                //force width value (do not take minColWidth option if a width value is set in the html column schema)
                                colSchema.width = jqColumn.toIntOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnWidth, minColWidth)
                                colSchema.isAction = true;
                            }
                            if (colType === "action" && actionType === "deleteItem") {
                                colSchema.formatter = jqGrid.deleteItemFormatter;
                                colSchema.unformat = jqGrid.deleteItemUnformatter;
                                colSchema.isDeleteAction = true;
                                
                            }

                            if (colType === "actionValidator") {
                                //fix the width of the action
                                colSchema.fixed = true;
                                colSchema.search = false;
                                //force width value (do not take minColWidth option if a width value is set in the html column schema)
                                colSchema.width = jqColumn.toIntOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnWidth, minColWidth)
                                colSchema.isActionValidator = true;

                                colSchema.formatter = "defaultFormat";
                                //colSchema.edittype = "checkbox";
                                
                            }

                            if (colType === "actionValidator" && actionType === "deleteItem") {
                                colSchema.isDeleteActionValidator = true;
                            }

                            //get the column locked attribute
                            colSchema.isLocked = jqColumn.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnLocked, false);
                            if (colSchema.isLocked) {
                                colSchema.editable = false;
                                jqGrid.hasLockedColumns = true;
                            }

                            //setup CSS classes
                            var cssClasses = jqColumn.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnCSS, "ui-ellipsis");
                            // always add ui-ellipsis css class
                            if (cssClasses.doesNotContain("ui-ellipsis")) {
                                cssClasses += " ui-ellipsis";
                            }
                            if (colSchema.editable === false) {
                                cssClasses += " vp-grid-not-editable";
                            }
                            if (colSchema.editable === true) {
                                cssClasses += " vp-grid-editable";
                            }

                            if (colSchema.isLocked) {
                                cssClasses += " vp-grid-locked";
                            }
                            colSchema.classes = cssClasses;

                            //bind internal vpGrid cell editing validator
                            colSchema.editrules = colSchema.editrules || {};
                            colSchema.editrules.custom = true;
                            colSchema.editrules.custom_func = function (value, colTitle, iCol) {
                                try {
                                    var validationResult = jqGrid.options.afterValidateCell(value, colTitle, iCol);
                                    return validationResult;
                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                            }

                            //get the column required attribute
                            colSchema.editrules.required = jqColumn.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnRequired, false);

                            //bind cellattr method 
                            colSchema.cellattr = function (rowid, cellValue, p1, p2, p3) {
                                try {
                                    //TODO : to be tested and finished
                                    var htmlAttributes = jqGrid.options.beforeRenderingCell(rowid, cellValue, p1, p2, p3);
                                    return htmlAttributes;

                                } catch (e) {
                                    vpGrid.logException(e);
                                    return "";
                                }

                            }


                            //get the column info
                            colSchema.hasInfo = false;
                            var colInfo = jqColumn.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnInfo, "");
                            //TODO : check this property does not conflict with next jqGrid version
                            colSchema.info = colInfo;
                            if (colInfo.isNotNullOrEmptyOrWhitespace()) {
                                colSchema.hasInfo = true;
                            }

                            //get the summary always update flag
                            colSchema.alwaysUpdateSummaryCell = jqColumn.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnSummaryAlwaysUpdate, false)


                            //build jqGrid options
                            colNames.push(colSchema.title);
                            colModel.push(colSchema);

                        } //end for (var i = 0; i < columnsCount; i++) {

                        jqGrid.options.colNames = colNames;
                        jqGrid.options.colModel = colModel;

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function buildGroupHeadersOptions(element) {
                    try {
                        var selector = "th[" + vpGrid.HtmlDataTag.ColumnName + "]";
                        var jqGroupHeaders = $(element).find(selector);

                        if (jqGroupHeaders.notFound()) {
                            //TODO : log
                            return {};
                        }

                        var groupHeaders = [];

                        var headersCount = jqGroupHeaders.length;
                        for (var i = 0; i < headersCount; i++) {
                            var jqGroupHeader = $(jqGroupHeaders[i]);
                            var headerGroupSchema = {};
                            // get the colspan
                            var numberOfColumns = jqGroupHeader.toIntOrDefaultFromAttribute("colspan", 1);
                            if (numberOfColumns <= 1) {
                                vpGrid.logError({
                                    message: "colspan attribute value is : " + numberOfColumns + " on element : " + outerHtml(jqGroupHeader[0]) + " should be >= 2. This group header is not processed."
                                });
                                continue;
                            }
                            headerGroupSchema.numberOfColumns = numberOfColumns;


                            //get the column name
                            var startColumnName = jqGroupHeader.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.ColumnName, "");
                            if (startColumnName.isNullOrEmptyOrWhitespace()) {
                                vpGrid.logError({
                                    message: "Data attribute : " + vpGrid.HtmlDataTag.ColumnName + " on element : " + outerHtml(jqGroupHeader[0]) + " is empty or invalid. This group header is not processed."
                                });
                                continue;
                            }
                            //TODO : check if startColumnName is a real column

                            headerGroupSchema.startColumnName = startColumnName;

                            // get the title of the group header
                            headerGroupSchema.titleText = jqGroupHeader.html();

                            //build jqGrid group Headers
                            groupHeaders.push(headerGroupSchema);

                        } //end for (var i = 0; i < headersCount; i++)

                        var groupHeadersOptions = {
                            useColSpanStyle: false,
                            groupHeaders: groupHeaders
                        }

                        return groupHeadersOptions;

                    } catch (e) {
                        vpGrid.logException(e);
                        return {}
                    }
                }

                function showWelcomeMessage() {

                }

                function showLoadingMessage(rowData) {
                    try {
                        //var jqContainer = vpGrid.currentContainer();

                        //if (jqContainer.notFound()) {
                        //    //TODO : log
                        //    return;
                        //}

                        var selector = "div[role=" + vpGrid.HtmlRoleAttribute.vpGridModalDialog + "]";
                        var jqElements = $(selector);

                        if (jqElements.notFound()) {
                            //TODO : log info
                            return;
                        }

                        var elementsCount = jqElements.length;
                        for (var i = 0; i < elementsCount; i++) {
                            var element = jqElements[i];
                            var jqElement = $(element);

                            var dialogId = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DialogId, "");
                            if (dialogId !== "vpGridLoading") {
                                continue;
                            }

                            //show modal dialog
                            jqElement.dialog("open");
                            return;

                        } // end for (var i = 0; i < elementsCount; i++)

                        //TODO : log no dialog mode found

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function hideLoadingMessage() {
                    try {
                        //var jqContainer = vpGrid.currentContainer();

                        //if (jqContainer.notFound()) {
                        //    //TODO : log
                        //    return;
                        //}

                        var selector = "div[role=" + vpGrid.HtmlRoleAttribute.vpGridModalDialog + "]";
                        var jqElements = $(selector);

                        if (jqElements.notFound()) {
                            //TODO : log info
                            return;
                        }

                        var elementsCount = jqElements.length;
                        for (var i = 0; i < elementsCount; i++) {
                            var element = jqElements[i];
                            var jqElement = $(element);

                            var dialogId = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DialogId, "");
                            if (dialogId !== "vpGridLoading") {
                                continue;
                            }

                            //show modal dialog
                            jqElement.dialog("close");
                            return;

                        } // end for (var i = 0; i < elementsCount; i++)

                        //TODO : log no dialog mode found

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function showDeleteItemMessage(rowid) {
                    try {
                        
                        var element = vpGrid.tryFindModalDialogByName("vpGridDeleteItem");
                        var jqElement = $(element);

                        if (jqElement.notFound()) {
                            //TODO : log info
                            return;
                        }

                        // inject vpGrid property bag in the div dialog

                        //explictely show the selected row to be deleted
                        var jqRow = jqGrid.row(rowid);
                        jqRow.addClass('ui-state-to-be-deleted');

                        //show modal dialog
                        jqElement.on("dialogclose", function (event, ui) {
                            try {
                                //unselect the selected row
                                jqRow.removeClass('ui-state-to-be-deleted');


                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });

                        jqElement.dialog("open");

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function showCannotDeleteItemMessage(rowid) {
                    try {

                        var element = vpGrid.tryFindModalDialogByName("vpGridCannotDeleteItem");
                        var jqElement = $(element);

                        if (jqElement.notFound()) {
                            //TODO : log info
                            return;
                        }

                        // inject vpGrid property bag in the div dialog

                        //explictely show the selected row to be deleted
                        var jqRow = jqGrid.row(rowid);
                        jqRow.addClass('ui-state-to-be-deleted');

                        //show modal dialog
                        jqElement.on("dialogclose", function (event, ui) {
                            try {
                                //unselect the selected row
                                jqRow.removeClass('ui-state-to-be-deleted');


                            } catch (e) {
                                vpGrid.logException(e);
                            }
                        });

                        jqElement.dialog("open");

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function showEmptyMessageOnLoad() {
                    try {

                        var jqContainer = vpGrid.currentContainer();

                        if (jqContainer.notFound()) {
                            //TODO : log
                            return;
                        }

                        var selector = "div[role=" + vpGrid.HtmlRoleAttribute.vpGridPartialUI + "]";
                        selector += "[" + vpGrid.HtmlDataTag.UIIdentifier + "=vpGridEmptyOnDataLoad" + "]";
                        var jqElements = $(selector);

                        if (jqElements.notFound()) {
                            //TODO : log info
                            return;
                        }

                        // check if the found element is already in place
                        var isInPlace = jqElements.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.UIInPlace, false);
                        if (isInPlace) {
                            jqElements.showEx();
                            return;
                        }

                        var jqGridContentArea = jqGrid.contentArea();

                        if (jqGridContentArea.notFound()) {
                            vpGrid.logError({
                                functionName: "showEmptyMessageOnLoad",
                                message: "jqGrid content area not found."
                            });
                        }

                        jqElements.appendTo(jqGridContentArea);
                        jqElements.attr(vpGrid.HtmlDataTag.UIInPlace, 'true');
                        jqElements.showEx();

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function hideEmptyMessageOnLoad() {
                    try {

                        var jqContainer = vpGrid.currentContainer();

                        if (jqContainer.notFound()) {
                            //TODO : log
                            return;
                        }

                        var selector = "div[role=" + vpGrid.HtmlRoleAttribute.vpGridPartialUI + "]";
                        selector += "[" + vpGrid.HtmlDataTag.UIIdentifier + "=vpGridEmptyOnDataLoad" + "]";
                        var jqElements = $(selector);

                        if (jqElements.notFound()) {
                            //TODO : log info
                            return;
                        }

                        jqElements.hideEx();

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function showEmptyMessageOnGridComplete() {
                    try {

                        var jqContainer = vpGrid.currentContainer();

                        if (jqContainer.notFound()) {
                            //TODO : log
                            return;
                        }

                        var selector = "div[role=" + vpGrid.HtmlRoleAttribute.vpGridPartialUI + "]";
                        selector += "[" + vpGrid.HtmlDataTag.UIIdentifier + "=vpGridEmptyOnGridComplete" + "]";
                        var jqElements = $(selector);

                        if (jqElements.notFound()) {
                            //TODO : log info
                            return;
                        }

                        // check if the found element is already in place
                        var isInPlace = jqElements.toBooleanOrDefaultFromAttribute(vpGrid.HtmlDataTag.UIInPlace, false);
                        if (isInPlace) {
                            jqElements.showEx();
                            return;
                        }

                        var jqGridContentArea = jqGrid.contentArea();

                        if (jqGridContentArea.notFound()) {
                            vpGrid.logError({
                                functionName: "showEmptyMessageOnGridComplete",
                                message: "jqGrid content area not found."
                            });
                        }

                        jqElements.appendTo(jqGridContentArea);
                        jqElements.attr(vpGrid.HtmlDataTag.UIInPlace, 'true');
                        jqElements.showEx();

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function hideEmptyMessageOnGridComplete() {
                    try {

                        var jqContainer = vpGrid.currentContainer();

                        if (jqContainer.notFound()) {
                            //TODO : log
                            return;
                        }

                        var selector = "div[role=" + vpGrid.HtmlRoleAttribute.vpGridPartialUI + "]";
                        selector += "[" + vpGrid.HtmlDataTag.UIIdentifier + "=vpGridEmptyOnGridComplete" + "]";
                        var jqElements = $(selector);

                        if (jqElements.notFound()) {
                            //TODO : log info
                            return;
                        }

                        jqElements.hideEx();

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.placeSummaryRowsOnTop = function () {
                    /// <signature>
                    /// <summary>Move the summary row at the top under the jqGrid headers (the summary row is placed by default at the bottom of jqGrid)</summary>
                    /// </signature>
                    try {

                        if (jqGrid.options.toprow === false) {
                            // there is no summary row
                            return;
                        }


                        var jqBody = jqGrid.body();
                        var jqSummaryRowsContainer = jqGrid.summaryRowsContainer();

                        if (jqSummaryRowsContainer.notFound()) {
                            vpGrid.logError({
                                functionName: "jqGrid.placeSummaryRowsOnTop",
                                message: "Summary Rows Container not found : cannot be placed on top. Summary row(s) cannot be placed on top."
                            });
                            return;
                        }

                        jqSummaryRowsContainer = jqSummaryRowsContainer.detach();
                        jqSummaryRowsContainer.insertBefore(jqBody);

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.createAdditionalSummaryRows = function () {
                    /// <signature>
                    /// <summary>Add additional footer rows if needed</summary>
                    /// </signature>
                    try {

                        if (jqGrid.options.numberOfSummaryRows === 1) {
                            // there is no additional summary row
                            // do not modify default jqGrid behavior
                            return;
                        }

                        var jqSummaryRowsContainer = jqGrid.summaryRowsContainer();

                        if (jqSummaryRowsContainer.notFound()) {
                            vpGrid.logError({
                                functionName: "jqGrid.createAdditionalSummaryRows",
                                message: "Summary Rows container not found. Additional summary row(s) cannot be added."
                            });
                            return;
                        }

                        var defaultSummaryRowSelector = "tr[role=row].footrow";
                        var jqDefaultSummaryRow = jqSummaryRowsContainer.find(defaultSummaryRowSelector);
                        if (jqDefaultSummaryRow.notFound()) {
                            vpGrid.logError({
                                functionName: "jqGrid.createAdditionalSummaryRows",
                                message: "Cannot find default summary row : '" + jqDefaultSummaryRow.selector + "'"
                            });
                            return;
                        }

                        //add additional summary rows
                        var rowsCount = jqGrid.options.numberOfSummaryRows;
                        var jqTableBody = jqDefaultSummaryRow.parent();
                        for (var i = 1; i < rowsCount; i++) {
                            var jqClonedSummaryRow = jqDefaultSummaryRow.clone()
                            var j = i + 1;
                            var summaryRowId = "SummaryRow" + j ;
                            var summaryRowClassName = "summary-row-" + j ;
                            jqClonedSummaryRow.attr(vpGrid.HtmlDataTag.UIIdentifier, summaryRowId);
                            jqClonedSummaryRow.addClass(summaryRowClassName);

                            jqClonedSummaryRow.appendTo(jqTableBody);
                        }

                        //tag default summary row with vp grid id
                        jqDefaultSummaryRow.attr(vpGrid.HtmlDataTag.UIIdentifier, "SummaryRow1");
                        jqDefaultSummaryRow.addClass("summary-row-1");

                        jqSummaryRowsContainer.height(jqSummaryRowsContainer.height() * rowsCount);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                // row checkbox managment
                jqGrid.lastSelectedCheckboxId = "";
                jqGrid.currentSelectedCheckboxId = "";

                function uncheckRow(checkboxId) {
                    try {
                        if (isNotString(checkboxId)) {
                            vpGrid.logError({
                                functionName: "uncheckRow",
                                message: "checkboxId is not a string"
                            });
                            return;
                        }

                        if (checkboxId.isNullOrEmptyOrWhitespace()) {
                            return;
                        }

                        var checkboxSelector = "input[type=checkbox][id=" + checkboxId + "]";
                        var jqCheckbox = $(checkboxSelector);

                        if (jqCheckbox.notFound()) {
                            vpGrid.logError({
                                functionName: "uncheckRow",
                                message: "Cannot find checkbox : '" + jqCheckbox.selector + "'"
                            });
                            return;
                        }

                        jqCheckbox[0].checked = false;
                        jqCheckbox.removeAttr('checked');
                        jqCheckbox.closest("tr[role=row]").removeClass('ui-state-highlight');

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function checkRow(checkboxId) {
                    try {
                        if (isNotString(checkboxId)) {
                            vpGrid.logError({
                                functionName: "checkRow",
                                message: "checkboxId is not a string"
                            });
                            return;
                        }

                        if (checkboxId.isNullOrEmptyOrWhitespace()) {
                            return;
                        }

                        var checkboxSelector = "input[type=checkbox][id=" + checkboxId + "]";
                        var jqCheckbox = $(checkboxSelector);

                        if (jqCheckbox.notFound()) {
                            vpGrid.logError({
                                functionName: "checkRow",
                                message: "Cannot find checkbox : '" + jqCheckbox.selector + "'"
                            });
                            return;
                        }

                        jqCheckbox[0].checked = true;
                        //jqCheckbox.removeAttr('checked');
                        //jqCheckbox.closest("tr[role=row]").removeClass('ui-state-highlight');

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                function ensureOnlyOneRowCanBeChecked() {
                    try {
                        if (vpGridOptions.enableMultiSelect) {
                            // multi select is authorized
                            return;
                        }

                        //bind click event handler on every checkbox item
                        var jqRowCheckboxes = jqGrid.rowCheckboxes();

                        if (jqRowCheckboxes.notFound()) {
                            //TODO : log
                            return;
                        }

                        jqRowCheckboxes.bind('change', function (e) {
                            try {
                                if (this.checked === false) {
                                    
                                    return;
                                }

                                if (isNullOrUndefinedOrEmpty(this.id)) {
                                    
                                    return;
                                }

                                if (jqGrid.lastSelectedCheckboxId === this.id) {
                                    
                                    return;
                                }

                                var id1 = this.id;
                                var id2 = jqGrid.lastSelectedCheckboxId;
                                executeAsync(this,function () {
                                    try {
                                        uncheckRow(id2);
                                        checkRow(id1);
                                        jqGrid.currentSelectedCheckboxId = id1;
                                        jqGrid.lastSelectedCheckboxId = id1;
                                        
                                    } catch (ex) {
                                        vpGrid.logException(ex);
                                    }
                                    finally {
                                        executeAsync(this, function () {
                                            activateDeactivateRibbonContent();
                                        }, 100);
                                    }
                                }, 100);


                            } catch (ex) {
                                vpGrid.logException(ex);
                            }
                            finally {
                                e.stopPropagation();
                                executeAsync(this, function () {
                                    activateDeactivateRibbonContent();
                                }, 100);
                            }
                        });

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }


                function activateDeactivateRibbonContent() {
                    try {
                        
                        //bind click event handler on every checkbox item
                        var jqRowCheckboxes = jqGrid.rowCheckboxes();

                        if (jqRowCheckboxes.notFound()) {
                            //TODO : log
                            return;
                        }

                        var itemCount = jqRowCheckboxes.length;
                        var selectedItemCount = 0;
                        for (var i = 0; i < itemCount; i++) {
                            var checkbox = jqRowCheckboxes[i];
                            if (checkbox.checked) {
                                selectedItemCount += 1;
                            }
                        }

                        //get all buttons that have the data attribute data-vp-grid-ui-disabled-on
                        var jqRibbonContainer = jqGrid.ribbonContainer();
                        if (jqRibbonContainer.notFound()) {
                            //TODO : log
                            return;
                        }

                        var buttonsSelector = "button[" + vpGrid.HtmlDataTag.UIDisabledOn + "]";
                        var jqButtons = jqRibbonContainer.find(buttonsSelector);
                        if (jqButtons.notFound()) {
                            //TODO : log
                            return;
                        }

                        var buttonsCount = jqButtons.length;
                        for (var i = 0; i < buttonsCount; i++) {
                            var button = jqButtons[i];
                            var jqButton = $(button);
                            var disabledOn = jqButton.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.UIDisabledOn, "");
                            if (disabledOn === "noItemSelected" && selectedItemCount === 0) {
                                jqButton.attr('disabled', true).addClass("ui-state-disabled");
                                continue;
                            }

                            if (disabledOn === "noItemSelected" && selectedItemCount > 0) {
                                jqButton.removeAttr('disabled').removeClass("ui-state-disabled");
                                continue;
                            }

                            //TODO : raise event to enable listener activate/decativate button 

                            //TODO : log disableOn value not implemented
                            vpGrid.logError({
                                functionName : "activateDeactivateRibbonContent",
                                message: "Data attribute '" + vpGrid.HtmlDataTag.UIDisabledOn + "' has a not implemented value : '" + disabledOn + "' on element : \n " + outerHtml(button)
                            });

                        }

                        

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }






                // end // row checkbox managment

                jqGrid.bindAutocompleteOnSearchInputs = function () {
                    /// <signature>
                    /// <summary>bind autocomplete widget on search input boxes within the search toolbar</summary>
                    /// </signature>
                    try {
                        // check if search tool bar functionnality  is enabled
                        if (vpGridOptions.enableFilterToolbar === false) {
                            return;
                        }

                        var jqElements = jqGrid.searchToolbarInputs();
                        var count = jqElements.length;
                        for (var i = 0; i < count; i++) {
                            var element = jqElements[i];
                            var jqElement = $(element);
                            var colname = jqElement.toStringOrDefaultFromAttribute("name", "");
                            if (colname.isNullOrEmptyOrWhitespace()) {
                                continue;
                            }
                            var colValues = jqGrid.colValues(colname);
                            if (isNullOrUndefinedOrEmpty(colValues)) {
                                continue;
                            }

                            bindAutoCompleteWidgetWithDataOnElement(element, colValues);

                            // bind to select event to programmatically filter the grid 
                            jqElement.on("autocompleteselect", function (event, ui) {
                                try {
                                    executeAsync(this,jqGrid.filterGridFromSearchToolbar);

                                } catch (e) {
                                    vpGrid.logException(e);
                                }

                            });


                        }


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.currentColModels = function () {
                    try {
                        // get the jqGrid host table
                        var jqGridHost = jqGrid.host();

                        if (jqGridHost.notFound()) {
                            vpGrid.logError({
                                message: "Cannot get colModels jqGrid object because jqGrid host is not found."
                            });
                            return null;
                        }

                        var colModels = jqGridHost.jqGrid('getGridParam', 'colModel');
                        return colModels;

                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }
                }

                jqGrid.colModelOf = function (colName) {
                    /// <signature>
                    /// <summary>Get the colmodel the named column.</summary>
                    /// <param name="colName" type="String">Name of the column from which to get the colModel.</param>
                    /// <returns type="Object">Returns the colModel object of the column. Returns null if colModel is not found.</returns>
                    /// </signature>
                    try {
                        if (isNotString(colName)) {
                            //TODO : log
                            return null;
                        }

                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                message: "ColModels not found : jqGrid.colModelOf is stopped. colName='" + colName + "'"
                            });
                            return;
                        }

                        var colCount = colModels.length;
                        for (var i = 0; i < colCount; i++) {
                            var colModel = colModels[i];
                            var cellName = colModel.name;
                            if (colModel.name === colName) {
                                return colModel;
                            }
                        }
                        

                        return null;


                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }

                }

                jqGrid.colIndexOf = function (colName) {
                    /// <signature>
                    /// <summary>Get the column index (iCol) for the named column.</summary>
                    /// <param name="colName" type="String">Name of the column from which to get the index of the column</param>
                    /// <returns type="Number">Returns the index of the column. Returns -1 if column is not found.</returns>
                    /// </signature>
                    try {
                        if (isNotString(colName)) {
                            //TODO : log
                            return -1;
                        }

                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                message: "ColModels not found : jqGrid.colIndexOf is stopped. colName='" + colName + "'"
                            });
                            return;
                        }

                        var colCount = colModels.length;
                        for (var i = 0; i < colCount; i++) {
                            var colModel = colModels[i];
                            var cellName = colModel.name;
                            if (colModel.name === colName) {
                                return i;
                            }
                        }


                        return -1;


                    } catch (e) {
                        vpGrid.logException(e);
                        return -1;
                    }

                }

                jqGrid.rowData = function (rowId) {
                    try {
                        // get the jqGrid host table
                        var jqGridHost = jqGrid.host();

                        if (jqGridHost.notFound()) {
                            vpGrid.logError({
                                message: "Cannot get rowData object because jqGrid host is not found."
                            });
                            return null;
                        }

                        if (isNullOrUndefinedOrEmpty(rowId)) {
                            vpGrid.logError({
                                message: "input parameter is not valid. rowId value is : '" + rowId + "'"
                            });
                            return null;
                        }

                        var data = jqGridHost.jqGrid('getRowData', rowId);
                        return data;

                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }
                }

                jqGrid.selectedRowData = function () {
                    /// <signature>
                    /// <summary>Get the row data from the first selected Item.
                    ///         A selected item is a row for which the first column checkbox has been checked
                    ///</summary>
                    /// <returns type="Object">Returns a literal object that is the jqGrid datarow object.</returns>
                    /// </signature>
                    try {
                        // get the jqGrid host table
                        var jqGridHost = jqGrid.host();

                        if (jqGridHost.notFound()) {
                            vpGrid.logError({
                                message: "Cannot get rowData object because jqGrid host is not found."
                            });
                            return null;
                        }

                        var jqSelectedRow = jqGrid.selectedRow();

                        if (jqSelectedRow.notFound()) {
                            vpGrid.logError({
                                functionName: "jqGrid.selectedRowData",
                                message: "Current selected row cannot be found."
                            });
                            return null;
                        }

                        var rowId = jqSelectedRow[0].id;
                        if (isNullOrUndefinedOrEmpty(rowId)) {
                            vpGrid.logError({
                                functionName: "jqGrid.selectedRowData",
                                message: "input parameter is not valid. rowId value is : '" + rowId + "'"
                            });
                            return null;
                        }

                        var data = jqGridHost.jqGrid('getRowData', rowId);
                        return data;

                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }
                }



                jqGrid.emptyRowData = function () {
                    /// <signature>
                    /// <summary>Build a new data row literal object. 
                    ///         Each property is set with the default value defined in the colModel
                    ///</summary>
                    /// <returns type="Object">Litteral object where each property is an existing column. Returns null if something goes wrong.</returns>
                    /// </signature>
                    try {
                        var rowData = {};

                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                message: "ColModels not found : cannot build an empty data row object"
                            });
                            return null;
                        }

                        var colCount = colModels.length;
                        for (var i = 0; i < colCount; i++) {
                            var colModel = colModels[i];
                            var cellName = colModel.name;
                            rowData[cellName] = '';
                        }

                        return rowData;

                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }
                }

                jqGrid.rows = function () {
                    /// <signature>
                    /// <summary>Try to find all rows displayed in jqGrid</summary>
                    /// <returns type="Object">Returns the jqGrid table rows found by jQuery</returns>
                    /// </signature>
                    try {

                        var jqGridHost = jqGrid.host();
                        // first step : find all rows in jqGrid                        
                        var rowsSelector = "tr[role=row]";
                        var jqRows = jqGridHost.find(rowsSelector);

                        if (jqRows.notFound()) {
                            vpGrid.logError({
                                message: "Cannot find jqGrid rows because the following selector is not found : '" + jqRows.selector + "'",
                                functionName: "jqGrid.rows"
                            });
                        }

                        //update the total filtered item count
                        jqGrid.filteredItemCount = jqRows.length - 1;

                        return jqRows;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.isEmpty = function () {
                    /// <signature>
                    /// <summary>Check if the grid is empty</summary>
                    /// <returns type="Object">Returns true if the grid shows no data</returns>
                    /// </signature>
                    try {

                        var jqGridHost = jqGrid.host();
                        // first step : find all rows in jqGrid                        
                        var rowsSelector = "tr[role=row]";
                        var jqRows = jqGridHost.find(rowsSelector);

                        if (jqRows.notFound()) {
                            vpGrid.logError({
                                message: "Cannot find jqGrid rows because the following selector is not found : '" + jqRows.selector + "'",
                                functionName: "jqGrid.isEmpty"
                            });
                        }

                        if (jqRows.length === 1) {
                            return true;
                        }

                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                }

                jqGrid.unselectAllLines = function () {
                    try {
                        var jqRowCheckboxes = jqGrid.rowCheckboxes();

                        if (jqRowCheckboxes.found()) {
                            jqRowCheckboxes.removeAttr('checked');
                        }

                        //unhighlight all lines
                        var jqRows = jqGrid.rows();
                        jqRows.removeClass('ui-state-highlight');

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.rowCheckboxes = function () {
                    /// <signature>
                    /// <summary>Try to find, in jqFrid, all row checkboxes, excluding the one that is in the header</summary>
                    /// <returns type="Object">Returns the jqGrid checkboxes (used for item selection) found by jQuery</returns>
                    /// </signature>
                    try {

                        if (jqGrid.options.multiselect === false) {
                            // there is no checbox configured for row selection
                            return $(null);
                        }

                        var jqRows = jqGrid.rows();
                        // second step : find the cell in edit mode
                        var cellname = "cb";
                        var cellSelector = "td[role=gridcell][aria-describedby=" + jqGrid.Id + "_" + cellname + "]";
                        var jqCells = jqRows.find(cellSelector);
                        if (jqCells.notFound()) {
                            // TODO : log something if multiselect: true
                            return $(null);
                        }

                        //third step : find the input checkbox elements 
                        var jqCheckboxes = jqCells.find("input[type=checkbox]");

                        if (jqCheckboxes.notFound()) {
                            //TODO : log
                        }

                        return jqCheckboxes;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                jqGrid.hideHeaderCheckbox = function () {
                    /// <signature>
                    /// <summary>hide, in jqGrid, the checkbox that is in the header (first column on the left)</summary>
                    /// </signature>
                    try {

                        if (jqGrid.options.multiselect === false) {
                            // there is no checbox configured for row selection
                            return;
                        }

                        var jqGridContainer = jqGrid.container();
                        // first step : find row in jqGrid that hosts the header checkbox                        
                        var rowSelector = "tr[role=rowheader]";
                        var jqRow = jqGridContainer.find(rowSelector);
                        // second step : find the cell in edit mode
                        var cellname = "cb";
                        var cellSelector = "th[id=" + jqGrid.Id + "_" + cellname + "]";
                        var jqCell = jqRow.find(cellSelector);
                        if (jqCell.notFound()) {
                            vpGrid.logError({
                                message: "Cannot find selector : '" + jqCell.selector + "'",
                                functionName: "hideHeaderCheckbox"
                            });
                            return;
                        }

                        //third step : find the input checkbox elements 
                        var jqCheckbox = jqCell.find("input[type=checkbox]");

                        jqCheckbox.addClass('vp-grid-hidden');

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }
                }

                function onRowChecked() {

                }

                jqGrid.filterGridFromSearchToolbar = function () {
                    try {
                        // check if search tool bar functionnality  is enabled
                        if (vpGridOptions.enableFilterToolbar === false) {
                            return;
                        }

                        var jqGridHost = jqGrid.host();

                        if (jqGridHost.notFound()) {
                            vpGrid.logError({
                                message: "Cannot filter jqGrid rows because the following selector is not found : '" + jqGridHost.selector + "'",
                                functionName: "jqGrid.filterGridFromSearchToolbar"
                            });
                            return;
                        }

                        jqGridHost[0].triggerToolbar();

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.searchToolbarInputs = function () {
                    /// <signature>
                    /// <summary>Get all search input boxes within the search toolbar</summary>
                    /// </signature>
                    try {
                        var jqGridContainer = jqGrid.container();
                        if (jqGridContainer.notFound()) {
                            //TODO : log
                            return $(null);
                        }

                        // first step : find row in jqGrid that hosts the search toolbar                        
                        var rowSelector = "tr[role=rowheader].ui-search-toolbar";
                        var jqRow = jqGridContainer.find(rowSelector);

                        //second step : find search input boxes
                        var inputSelector = "input[type=text][id^=gs_]";
                        var jqInput = jqRow.find(inputSelector);
                        if (jqInput.notFound()) {
                            vpGrid.logError({
                                functionName: "jqGrid.searchToolbarInputs",
                                message: "Cannot configure input search toolbar because the following selector was not found : '" + jqInput.selector + "'",
                                info: "Check the version of the jqGrid library."
                            });
                            return $(null);
                        }

                        return jqInput;

                    } catch (e) {
                        vpGrid.logException(e);
                        return $(null);
                    }

                }

                jqGrid.colValues = function (colname) {
                    /// <signature>
                    /// <summary>Get all distinct values which are not null or empty from the named column.</summary>
                    /// <param name="colname" type="String">Name of the column from which to extract all values.</param>
                    /// <returns type="Array">Returns an array of non-null, non-empty, distinct values extracted from the column.Values are sorted asc.</returns>
                    /// </signature>
                    try {
                        if (isNotString(colname)) {
                            //TODO : log
                            return [];
                        }

                        var test = jqGrid.isReady;

                        if (isNullOrUndefined(jqGrid.originalData)) {
                            vpGrid.logError({
                                message: "Cannot get values in column '" + colname + "' because jqGrid.originalData array is not found."
                            });
                        }

                        if (isNotArray(jqGrid.originalData)) {
                            vpGrid.logError({
                                message: "Cannot get values in column '" + colname + "' because jqGrid.originalData is not an array of objects."
                            });
                        }

                        if (jqGrid.originalData.isEmpty()) {
                            return [];
                        }

                        var colValues = [];
                        var data = jqGrid.originalData;
                        var itemCount = data.length;

                        for (var i = 0; i < itemCount; i++) {
                            var dtoObject = data[i];
                            var propertyValue = dtoObject[colname];
                            if (isNullOrUndefined(propertyValue)) {
                                continue;
                            }
                            colValues.push(propertyValue);
                        }

                        var distinctValues = colValues.toUnique();
                        distinctValues = distinctValues.removeEmptyEntries();
                        if (distinctValues.isEmpty()) {
                            return [];
                        }

                        var sortedValues = distinctValues.sort();

                        return sortedValues;

                    } catch (e) {
                        vpGrid.logException(e);
                        return [];
                    }

                }

                function onDataReceived(eventArgs) {
                    try {
                        // make a backup copy of eventArgs
                        var eventArgsCopy = $.extend({}, eventArgs);

                        EventHandlers.raiseEvent(vpGrid.Event.onDataReceived, vpGrid, eventArgs);

                        // check possible misbehavior from listeners
                        if (isNullOrUndefinedOrEmpty(eventArgs)) {
                            vpGrid.logError({
                                functionName: "onDataReceived",
                                message: "eventArgs object corrupted by listener",
                                info: "eventArgs object is reverted to its original state"
                            });
                            $.extend(eventArgs, eventArgsCopy);
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(eventArgs.data)) {
                            eventArgs.data = eventArgsCopy.data;
                        }

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.loadDataComplete = function (xhr, textStatus) {
                    try {
                        //TODO : check if the grid is empty (because of no data from server)

                        setTimeout(function () {
                            try {
                                hideLoadingMessage();
                                //Show message in grid when no data loaded
                                if (jqGrid.isEmpty()) {
                                    showEmptyMessageOnLoad();
                                    return;
                                }

                                //hide empty message load

                            } catch (e) {
                                vpGrid.logException(e);
                            }

                        }, 1000);


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.loadData = function (timelineExecutionCallback) {
                    try {
                        //step 0 : show modal dialog loading
                        showLoadingMessage();

                        //step1 : gather all remote filters declared on the page
                        var data = jqGrid.remoteFilters();

                        //step2 : fetch data on remote server
                        var ajaxOptions = {
                            cache: false,
                            type: "GET",
                            dataType: "json",
                            success: jqGrid.loadDataFromWebResponse,
                            complete: function (xhr, textStatus) {
                                try {
                                    jqGrid.loadDataComplete(xhr, textStatus);

                                } catch (e) {
                                    vpGrid.logException(e);
                                }
                                finally {
                                    // continue timeline execution
                                    timelineExecutionCallback();
                                }
                            }
                        }

                        //get url to be requested
                        var crudOperations = vpGridOptions.crudOptions;
                        if (isNullOrUndefinedOrEmpty(crudOperations)) {
                            vpGrid.logError({
                                message: "CRUD operations are not defined in the vpGrid Options object. The grid cannot be loaded."
                            });
                            return;
                        }

                        if (isNullOrUndefinedOrEmpty(crudOperations.read)) {
                            vpGrid.logError({
                                message: "CRUD operation Read is not defined in the vpGrid Options object. The grid cannot be loaded."
                            });
                            return;
                        }

                        var requestUrl = crudOperations.read;
                        ajaxOptions.url = requestUrl;

                        if (isNotNullOrUndefinedOrEmpty(data)) {
                            ajaxOptions.data = data;
                        }

                        $.extend(ajaxOptions, vpGridAjaxOptions);

                        //TODO : raise event to enable listeners inspect and/or modify ajaxOptions

                        $.ajax(ajaxOptions);


                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }

                jqGrid.loadDataFromWebResponse = function (response) {
                    try {
                        if (isNullOrUndefinedOrEmpty(response)) {
                            vpGrid.logError({
                                functionName: "jqGrid.loadDataFromWebResponse",
                                message: "Server response is null or undefined.",
                                info: "Check if the server is up and running. Check also if the crud options are correctly configured when calling vpGrid.init function."
                            });
                            return;
                        }

                        //TODO : raise event so that listeners can inspect and/or modify response object

                        if (isNullOrUndefined(response.data)) {
                            vpGrid.logError({
                                functionName: "jqGrid.loadDataFromWebResponse",
                                message: "response.data object is null or undefined.",
                                info: "response.data is forced to be an empty array."
                            });
                            response.data = [];
                        }

                        var receivedData = response.data;
                        var itemCount = receivedData.length;

                        //raise event so that listeners can inspect and/or modify response data
                        var eventArgs = {
                            data: receivedData
                        }
                        onDataReceived(eventArgs);
                        var data = eventArgs.data;

                        // get the jqGrid host table
                        var jqGridHost = jqGrid.host();

                        //clear grid content
                        jqGridHost.jqGrid('clearGridData', true);

                        //set number of rows in jqGrid
                        var gridOptions = {
                            rowNum: itemCount
                        };
                        jqGridHost.jqGrid('setGridParam', gridOptions);

                        //keep track of received data 
                        jqGrid.originalData = data.duplicate();

                        //save total item count
                        jqGrid.totalItemCount = itemCount;

                        for (var i = 0; i < itemCount; i++)
                            jqGridHost.jqGrid('addRowData', i + 1, data[i]);

                    } catch (e) {
                        vpGrid.logException(e);
                    }
                    finally {
                        // execute handler onGridLoaded
                        //VP.Timesheet.ExecuteAsync(VP.Timesheet.EventHandlers.LoadGridEvents.onGridLoaded);
                    }
                }

                jqGrid.remoteFilters = function () {
                    try {
                        // get root node of vpGrid
                        var jqRootNode = jqGrid.container();
                        if (jqRootNode.notFound()) {
                            //TODO : log
                            return {};
                        }

                        var selector = "[role=" + vpGrid.HtmlRoleAttribute.RemoteDataFilter + "]";
                        var jqElements = jqRootNode.find(selector);

                        if (jqElements.notFound()) {
                            //TODO : log
                            return {};
                        }

                        var filters = {};
                        var elementsCount = jqElements.length;
                        for (var i = 0; i < elementsCount; i++) {
                            var element = jqElements[i];
                            var jqElement = $(element);

                            //get the name of the filter key
                            var filterKey = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.RemoteDataFilterKey, "Filter");
                            var filterName = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.RemoteDataFilterName, "");
                            var filterOperator = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.RemoteDataFilterOperator, "eq");
                            var filterValue = jqElement.val();

                            if (isNullOrUndefinedOrEmpty(filterValue)) {
                                // this filter must be ignored
                                continue;
                            }

                            if (filterName.isNullOrEmptyOrWhitespace()) {
                                //TODO : log
                                vpGrid.logError({
                                    message: "data attribute : " + vpGrid.HtmlDataTag.RemoteDataFilterName + " is not defined on element : " + outerHtml(element) + ". This remote data filter is ignored."
                                });
                                continue;
                            }

                            var query = filterName + " " + filterOperator + " " + filterValue;
                            // check if the key has already been setup as a property
                            var filter = {};
                            filter[filterKey] = query;
                            extendOrMerge(filters, filter);

                        } // end for (var i = 0; i < elementsCount; i++)

                        return filters;

                    } catch (e) {
                        vpGrid.logException(e);
                        return {}
                    }
                }

                jqGrid.colExists = function (colName) {
                    /// <signature>
                    /// <summary>Check if the column with the specified name exists</summary>
                    /// <param name="colname" type="String">Name of the column</param>
                    /// <returns type="Boolean">Returns true if the column exists in jqGrid colModel</returns>
                    /// </signature>
                    try {
                        if (isNotString(colName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.colExists",
                                message: "Input column name is not a valid string."
                            });
                            return false;
                        }

                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                message: "ColModels not found."
                            });
                            return false;
                        }

                        var colCount = colModels.length;
                        for (var i = 0; i < colCount; i++) {
                            var colModel = colModels[i];
                            var cellName = colModel.name;
                            if (colModel.name === colName) {
                                return true;
                            }
                        }

                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }

                }
                jqGrid.colDoesNotExist = function (colName) {
                    return jqGrid.colExists(colName) === false;
                }

                jqGrid.sumOf = function (colName) {
                    /// <signature>
                    /// <summary>Get the sum of all values from the named column.</summary>
                    /// <param name="colname" type="String">Name of the column from which to extract all values.</param>
                    /// <returns type="Number">Returns the sum of all values in the column. Returns NaN if something goes wrong.</returns>
                    /// </signature>
                    try {
                        if (jqGrid.colDoesNotExist(colName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.sumOf",
                                message: "Input column name is not a valid column name",
                                info: "The name of the column is case sensitive. Check the name or check the column still exists."
                            });
                            return NaN;
                        }

                        var jqGridHost = jqGrid.host();
                        var result = jqGridHost.jqGrid('getCol', colName, false, 'sum');

                        return result;


                    } catch (e) {
                        vpGrid.logException(e);
                        return NaN;
                    }

                }

                jqGrid.filteredSumOf = function (colName, filter) {
                    /// <signature>
                    /// <summary>Get the sum of all values from the named column.</summary>
                    /// <param name="colname" type="String">Name of the column from which to extract all values.</param>
                    /// <param name="filter" type="Function">function that is called on every row in the grid. Must return a boolean value.</param>
                    /// <returns type="Number">Returns the sum of all values in the column. Returns NaN if something goes wrong.</returns>
                    /// </signature>
                    try {
                        if (jqGrid.colDoesNotExist(colName)) {
                            vpGrid.logError({
                                functionName: "jqGrid.filteredSumOf",
                                message: "Input column name is not a valid column name",
                                info: "The name of the column is case sensitive. Check the name or check the column still exists."
                            });
                            return NaN;
                        }

                        if (isNotFunction(filter)) {
                            vpGrid.logError({
                                functionName: "jqGrid.filteredSumOf",
                                message: "filter callback is not a valid function",
                                info: "Check that function : '" + filter + "' exists in your code."
                            });
                            return NaN;
                        }

                        var jqGridHost = jqGrid.host();
                        var result = jqGridHost.jqGrid('getFilteredCol', colName, false, 'sum', filter);

                        return result;


                    } catch (e) {
                        vpGrid.logException(e);
                        return NaN;
                    }

                }

                jqGrid.keyColumnName = function () {
                    /// <signature>
                    /// <summary>Get the name of the column that holds the primary key.
                    ///         -> the primary key column is defined in the column schema with 
                    ///            the data attribute : data-vp-grid-column-type='key'
                    ///</summary>
                    /// <returns type="String">Returns the name of the found column. Returns null if the column is not found.</returns>
                    /// </signature>
                    try {
                        
                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                functionName : 'keyColumnName',
                                message: "ColModels not found."
                            });
                            return null;
                        }

                        var colCount = colModels.length;
                        for (var i = 0; i < colCount; i++) {
                            var colModel = colModels[i];
                            var colName = colModel.name;
                            if (colModel.isKey) {
                                return colName;
                            }
                        }

                        vpGrid.logError({
                            functionName: 'keyColumnName',
                            message: "The primary key column has not been found.",
                            info : "Check col schema. One column should have the following data attribute : '" + vpGrid.HtmlDataTag.ColumnType + "'='key'."
                        });

                        return null;

                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }

                }

                jqGrid.deleteActionValidatorColumnName = function () {
                    /// <signature>
                    /// <summary>Get the name of the column that holds the actionValidator info for the action of deleting an item.
                    ///         -> the action validator for deleteItem column is defined in the column schema with 
                    ///            the data attribute : data-vp-grid-column-type="actionValidator"
                    ///                                 data-vp-grid-column-actiontype="deleteItem"
                    ///</summary>
                    /// <returns type="String">Returns the name of the found column. Returns null if the column is not found.</returns>
                    /// </signature>
                    try {

                        var colModels = jqGrid.currentColModels();
                        if (isNullOrUndefinedOrEmpty(colModels)) {
                            vpGrid.logError({
                                functionName: 'deleteActionValidatorColumnName',
                                message: "ColModels not found."
                            });
                            return null;
                        }

                        var colCount = colModels.length;
                        for (var i = 0; i < colCount; i++) {
                            var colModel = colModels[i];
                            var colName = colModel.name;
                            if (colModel.isDeleteActionValidator) {
                                return colName;
                            }
                        }

                        vpGrid.logError({
                            functionName: 'deleteActionValidatorColumnName',
                            message: "The action validator for deleteItem has not been found.",
                            info: "Check col schema. One column should have the following data attributes : '" + vpGrid.HtmlDataTag.ColumnType + "'='actionValidator', '" + vpGrid.HtmlDataTag.ColumnActionType + "'='deleteItem', "
                        });

                        return null;

                    } catch (e) {
                        vpGrid.logException(e);
                        return null;
                    }

                }


                jqGrid.canDeleteRowWithId = function (rowId) {
                    /// <signature>
                    /// <summary>Check if the row with the specified HTML Id can be deleted.</summary>
                    /// <param name="rowId" type="String">HTML id of the table row <tr> element within jqGrid</param>
                    /// <returns type="Boolean">Returns true if the row can be deleted.</returns>
                    /// </signature>
                    try {

                        if (isNotString(rowId)) {
                            vpGrid.logError({
                                functionName: "canDeleteRowWithId",
                                message: "rowId is not a string but is :'" + rowId + "'"
                            });
                            return false;
                        }

                        var dataRow = jqGrid.rowData(rowId);
                        if (isNullOrUndefinedOrEmpty(dataRow)) {
                            return false;
                        }

                        // get the name of the column that holds the true/false info about if the row is deletable or not
                        var isDeletableColName = jqGrid.deleteActionValidatorColumnName();

                        if (isNullOrUndefinedOrEmpty(isDeletableColName)) {
                            return false;
                        }

                        if (isNotString(isDeletableColName)) {
                            return false;
                        }

                        //TODO : implement a real boolean property with specific formatter
                        if (dataRow[isDeletableColName] === "true") {
                            return true;
                        }

                        return false;

                    } catch (e) {
                        vpGrid.logException(e);
                        return false;
                    }
                }


                jqGrid.showUINotification = function (title, message, isPersistent) {
                    try {
                        if (isNullOrUndefinedOrEmpty(message)) {
                            return;
                        }

                        var containerSelector = 'div[id=vp-grid-ui-notification-area]';
                        var jqContainer = $(containerSelector);

                        if (jqContainer.notFound()) {
                            $('<div id="vp-grid-ui-notification-area" />').appendTo(document.body);
                            jqContainer = $(containerSelector);
                        }

                        jqContainer.position()
                        var target = $('.qtip.jgrowl:visible:last');

                        $('<div/>').qtip({
                            overwrite: true,
                            style: {
                                widget: true, // Use the jQuery UI widget classes
                                def: false, // Remove the default styling (usually a good idea, see below)
                                width: 250,
                                classes: 'jgrowl',
                                tip: false
                            },
                            content: {
                                text: message,
                                title: {
                                    text: title,
                                    button: true
                                }
                            },
                            position: {
                                target: [0, 0],
                                container: jqContainer
                            },
                            show: {
                                event: false,
                                ready: true,
                                effect: function () {
                                    $(this).stop(0, 1).animate({ height: 'toggle' }, 400, 'swing');
                                },
                                delay: 0,
                                persistent: isPersistent
                            },
                            hide: {
                                event: false,
                                effect: function (api) {
                                    $(this).stop(0, 1).animate({ height: 'toggle' }, 400, 'swing');
                                }
                            },
                            events: {
                                render: function (event, api) {
                                    if (!api.options.show.persistent) {
                                        $(this).bind('mouseover mouseout', function (e) {
                                            var lifespan = 5000;

                                            clearTimeout(api.timer);
                                            if (e.type !== 'mouseover') {
                                                api.timer = setTimeout(function () { api.hide(e) }, lifespan);
                                            }
                                        })
                                        .triggerHandler('mouseout');
                                    }
                                }
                            }

                        });



                    } catch (e) {
                        vpGrid.logException(e);
                    }
                }



            } catch (e) {
                vpGrid.logException(e);
            }
            finally {
                return jqGrid;
            }

        })(vpGridOptions);

        // end jqGrid layer

        // vpGrid public interface
        vpGrid.currentContainer = function () {
            try {
                var selector = "div[role=" + vpGrid.HtmlRoleAttribute.vpGridContainer + "]";
                var jqElement = $(selector);
                if (jqElement.notFound()) {
                    vpGrid.logError({
                        message: "no container div found (<div role='" + vpGrid.HtmlRoleAttribute.vpGridContainer + "'>" + ") found on page"

                    });
                    return $(null);
                }
                return jqElement;

            } catch (e) {
                vpGrid.logException(e);
                return $(null);
            }

        }

        vpGrid.totalItemCount = function () {
            try {
                var itemCount = JQGrid.totalItemCount;
                return itemCount;

            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.filteredItemCount = function () {
            try {
                var itemCount = JQGrid.filteredItemCount;
                return itemCount;

            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.sumOf = function (colName) {
            /// <signature>
            /// <summary>Get the sum of all values from the named column.</summary>
            /// <param name="colname" type="String">Name of the column on which to apply the sum operation.</param>
            /// <returns type="Number">Returns the sum of all values in the column. Returns NaN if something goes wrong.</returns>
            /// </signature>
            try {
                var result = JQGrid.sumOf(colName);
                return result;

            } catch (e) {
                vpGrid.logException(e);
                return NaN;
            }
        }

        vpGrid.filteredSumOf = function (colName, filter) {
            /// <signature>
            /// <summary>Get the sum of all values from the named column and from the rows that are filtered by the filter callback</summary>
            /// <param name="colname" type="String">Name of the column on which to apply the filtered sum operation.</param>
            /// <param name="filter" type="Function">function that is called on every row in the grid. Must return a boolean value.</param>
            /// <returns type="Number">Returns the sum of all values in the column of the filtered rows. Returns NaN if something goes wrong.</returns>
            /// </signature>
            try {
                var result = JQGrid.filteredSumOf(colName, filter);
                return result;

            } catch (e) {
                vpGrid.logException(e);
                return NaN;
            }
        }

        vpGrid.cellValue = function (rowid,colName) {
            /// <signature>
            /// <summary>Get the value of the cell located in a specific row and in a specific column.</summary>
            /// <param name="rowid" type="String">The id of the row (DOM id) where the cell is located</param>
            /// <param name="colname" type="String">Name of the column where the cell is located.</param>
            /// <returns type="Number">Returns the value in native format.</returns>
            /// </signature>
            try {
                var result = JQGrid.cellValue(rowid, colName);
                return result;

            } catch (e) {
                vpGrid.logException(e);
                return NaN;
            }
        }

        vpGrid.addNewItem = function (event,pos) {
            /// <signature>
            /// <summary>Insert a new row in the grid. Data is read from the current <form> DOM element.</summary>
            /// <param name="pos" type="String">Position of insertion. Valid values are : 'last' and 'first'</param>
            /// <returns type="void"></returns>
            /// </signature>
            try {
                var jqForm = $(this).closest('div.form-vp-grid-modal-dialog');
                var validationResult = jqForm.validateThisForm();
                if (isNullOrUndefinedOrEmpty(validationResult)) {
                    //TODO : log
                    return;
                }

                if (validationResult.isValid) {
                    jqForm.insertNewRowFromThisForm(pos);
                    $(this).closest('div[role=vp-grid-modal-dialog]').dialog('close');
                    return;
                }

                jqForm.showValidationErrorsOnThisForm(validationResult);
                
            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.updateItem = function (event, params) {
            /// <signature>
            /// <summary>Update an existing row in the grid. Data is read from the current <form> DOM element.</summary>
            /// <param name="event" type="Object">Literal object passed by the click event</param>
            /// <param name="params" type="String">Literal object to be merged to the updated row. 
            ///         This literal object will be injected in the ajax call to enable server to process custom updates.
            /// </param>
            /// <returns type="void"></returns>
            /// </signature>
            try {
                var jqForm = $(this).closest('div.form-vp-grid-modal-dialog');
                var validationResult = jqForm.validateThisForm();
                if (isNullOrUndefinedOrEmpty(validationResult)) {
                    //TODO : log
                    return;
                }

                if (validationResult.isValid) {
                    jqForm.updateRowFromThisForm(params);
                    $(this).closest('div[role=vp-grid-modal-dialog]').dialog('close');
                    return;
                }

                jqForm.showValidationErrorsOnThisForm(validationResult);

            } catch (e) {
                vpGrid.logException(e);
            }
        }










        vpGrid.insertNewRow = function (dataRow, pos) {
            /// <signature>
            /// <summary>Insert a new row in the grid</summary>
            /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
            /// <param name="pos" type="String">Position of insertion. Valid values are : 'last' and 'first'</param>
            /// <returns type="void"></returns>
            /// </signature>
            try {
                JQGrid.insertNewRow(dataRow, pos);
            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.updateRow = function (dataRow, params) {
            /// <signature>
            /// <summary>Update an exisintg row in the grid</summary>
            /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
            /// <param name="params" type="String">Literal object to be merged to the updated row. 
            /// <returns type="void"></returns>
            /// </signature>
            try {
                var customDataRow = $.extend({}, dataRow, params);
                JQGrid.options.updateRowWithFormData(customDataRow);
            } catch (e) {
                vpGrid.logException(e);
            }
        }








        vpGrid.insertNewRowAfterSelected = function (dataRow) {
            /// <signature>
            /// <summary>Insert a new row in the grid after the currently selected row.</summary>
            /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
            /// <returns type="void"></returns>
            /// </signature>
            try {
                JQGrid.insertNewRowAfterSelected(dataRow);
            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.insertInlineSummaryRowAfterSelected = function (dataRow) {
            /// <signature>
            /// <summary>Insert a new inline summary row in the grid after the currently selected row.</summary>
            /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
            /// <returns type="void"></returns>
            /// </signature>
            try {
                JQGrid.insertInlineSummaryRowAfterSelected(dataRow);
            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.insertInlineSummaryRowAfter = function (rowid, dataRow, summaryRowidPrefix) {
            /// <signature>
            /// <summary>Insert a new inline summary row in the grid after the row with id rowid.</summary>
            /// <param name="rowid" type="String">Dom id of the row after which to insert the summary row.</param>
            /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
            /// <param name="summaryRowidPrefix" type="String">Prefix that will be used to build the Dom id of the summary row that will be created. 
            ///             If not defined this parameter will receive the value : 'summaryAfter'
            ///             The Dom id of the summary row will have the value : summaryRowidPrefix + rowid
            ///             The data attribute "data-vp-grid-summary-id" will be automatically injected on the summary row :
            ///                     data-vp-grid-summary-id=summaryRowidPrefix
            ///                     -> this will be possible to create a summary row in the footer that is the sum of only inline summary rows with that data tag value
            /// </param>
            /// <returns type="void"></returns>
            /// </signature>
            try {
                JQGrid.insertInlineSummaryRowAfter(rowid, dataRow, summaryRowidPrefix);
            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.insertInlineSummaryRowBefore = function (rowid, dataRow, summaryRowidPrefix) {
            /// <signature>
            /// <summary>Insert a new inline summary row in the grid before the row with id rowid.</summary>
            /// <param name="rowid" type="String">Dom id of the row before which to insert the summary row.</param>
            /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
            /// <param name="summaryRowidPrefix" type="String">Prefix that will be used to build the Dom id of the summary row that will be created. 
            ///             If not defined this parameter will receive the value : 'summaryBefore'
            ///             The Dom id of the summary row will have the value : summaryRowidPrefix + rowid
            ///             The data attribute "data-vp-grid-summary-id" will be automatically injected on the summary row :
            ///                     data-vp-grid-summary-id=summaryRowidPrefix
            ///                     -> this will be possible to create a summary row in the footer that is the sum of only summary rows with that data tag value
            /// </param>
            /// <returns type="void"></returns>
            /// </signature>
            try {
                JQGrid.insertInlineSummaryRowBefore(rowid, dataRow, summaryRowidPrefix);
            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.updateInlineSummaryRowAfter = function (rowid, dataRow, summaryRowidPrefix) {
            /// <signature>
            /// <summary>Update an existing inline summary row in the grid after the row with id rowid.</summary>
            /// <param name="rowid" type="String">Dom id of the row after which to insert the summary row.</param>
            /// <param name="dataRow" type="Object">Literal object containing column values. Each property of this object must match a column name.</param>
            /// <param name="summaryRowidPrefix" type="String">Prefix that will be used to build the Dom id of the summary row that will be updated. 
            ///             If not defined this parameter will receive the value : 'summaryAfter'
            ///             The Dom id of the summary row will have the value : summaryRowidPrefix + rowid
            ///             The data attribute "data-vp-grid-summary-id" will be automatically injected on the summary row :
            ///                     data-vp-grid-summary-id=summaryRowidPrefix
            ///                     -> this will be possible to create a summary row in the footer that is the sum of only summary rows with that data tag value
            /// </param>
            /// <returns type="void"></returns>
            /// </signature>
            try {
                JQGrid.updateInlineSummaryRowAfter(rowid, dataRow, summaryRowidPrefix);
            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.deleteCurrentRow = function (event) {
            /// <signature>
            /// <summary>Event handler that deletes the currently selected row in the grid.</summary>
            /// <param name="event" type="Object">Literal object passed by the click event</param>
            /// <returns type="void"></returns>
            /// </signature>
            try {
                JQGrid.deleteCurrentRow();
                vpGrid.closeModalDialog(event);

            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.tryFindModalDialogByName = function (modalDialogName) {
            /// <signature>
            /// <summary>Find the jquery-ui modal dialog from its name. The name should be setup as a data attribute on the div dialog : 
            ///         <div role="vp-grid-modal-dialog"
            ///                 title="Suppression d'un item"
            ///                 class="vp-grid-hidden vp-grid-container vp-grid-modal-dialog"
            ///                 data-vp-grid-dialog-id="modalDialogName">
            ///          </div>   
            ///</summary>
            /// <param name="modalDialogName" type="String">Value of the 'data-vp-grid-dialog-id' data attribute on the div dialog.</param>
            /// <returns type="Object">Returns the found div dialog dom element. If the div dialog is not found, the function returns undefined.</returns>
            /// </signature>
            try {
                if (isNotString(modalDialogName)) {
                    vpGrid.logError({
                        functionName: "tryFindModalDialogByName",
                        message: "The name of the modal dialog is not a valid string. It's value is : '" + modalDialogName + "'"
                    });
                    return undefined;
                }

                var selector = "div[role=" + vpGrid.HtmlRoleAttribute.vpGridModalDialog + "]";
                var jqElements = $(selector);

                if (jqElements.notFound()) {
                    vpGrid.logError({
                        functionName: "tryFindModalDialogByName",
                        message: "Div Modal Dialog not found with selector : '" + selector + "'",
                        info: "Check that it exists a div with atrribute role='vp-grid-modal-dialog' and data attribute data-vp-grid-dialog-id='" + modalDialogName + "'"
                    });
                    return undefined;
                }

                var elementsCount = jqElements.length;
                for (var i = 0; i < elementsCount; i++) {
                    var element = jqElements[i];
                    var jqElement = $(element);

                    var dialogId = jqElement.toStringOrDefaultFromAttribute(vpGrid.HtmlDataTag.DialogId, "");
                    if (dialogId === modalDialogName) {
                        return element;
                    }
                } // end for (var i = 0; i < elementsCount; i++)


                vpGrid.logError({
                    functionName: "tryFindModalDialogByName",
                    message: "Div Modal Dialog not found.",
                    info: "Check that it exists a div with atrribute role='vp-grid-modal-dialog' and data attribute data-vp-grid-dialog-id='" + modalDialogName + "'"
                });

                return undefined;


            } catch (e) {
                vpGrid.logException(e);
                return undefined;
            }
        }

        vpGrid.closeModalDialog = function (event) {
            /// <signature>
            /// <summary>Event handler that closes the modal dialog window targeted by the input parameter event.</summary>
            /// <param name="event" type="Object">Literal object passed by the click event</param>
            /// </signature>
            try {
                if (isNullOrUndefinedOrEmpty(event)) {
                    //TODO : log
                    return;
                }

                if (isNullOrUndefinedOrEmpty(event.target)) {
                    vpGrid.logError({
                        message: "input parameter event is not a valid object : target property not found or not valid",
                        functionName: "vpGrid.closeModalDialog",
                        info: "Check that vpGrid.closeModalDialog is called by a click event on a DOM element."

                    });
                    return;
                }

                var target = event.target;
                var elementSelector = "div[role=vp-grid-modal-dialog]";
                var jqElement = $(target).closest(elementSelector);

                if (jqElement.notFound()) {
                    vpGrid.logError({
                        message: "Selector not found : '" + elementSelector + "'",
                        functionName: "vpGrid.closeModalDialog",
                        info: "Check that '" + elementSelector + "'" + " is parent of element :\n" + outerHtml(target)

                    });
                    return;
                }

                jqElement.dialog('close');


            } catch (e) {
                vpGrid.logException(e);
            }
        }

        vpGrid.openModalDialog = function (event,modalDialogId) {
            /// <signature>
            /// <summary>Event handler that opens the modal dialog window targeted by modalDialogId.</summary>
            /// <param name="event" type="Object">Literal object passed by the click event</param>
            /// <param name="modalDialogId" type="String">value of the data attribute 'data-vp-grid-dialog-id'</param>
            /// </signature>
            try {
                if (isNullOrUndefinedOrEmpty(event)) {
                    //TODO : log
                    return;
                }

                if (isNullOrUndefinedOrEmpty(event.target)) {
                    vpGrid.logError({
                        message: "input parameter event is not a valid object : target property not found or not valid",
                        functionName: "vpGrid.closeModalDialog",
                        info: "Check that vpGrid.openModalDialog is called by a click event on a DOM element."

                    });
                    return;
                }

                if (isNotString(modalDialogId)) {
                    vpGrid.logError({
                        message: "input parameter modalDialogId is not a valid string : '" + modalDialogId + "'",
                        functionName: "vpGrid.openModalDialog",
                        info: "Check that 'data-vp-grid-handlers' data attribute is correctly setup on the clicked button."
                    });
                    return;
                }
                
                var elementSelector = "div[role=vp-grid-modal-dialog][data-vp-grid-dialog-id=" + modalDialogId + "]";
                var jqElement = $(elementSelector);

                if (jqElement.notFound()) {
                    vpGrid.logError({
                        message: "Selector not found : '" + elementSelector + "'",
                        functionName: "vpGrid.openModalDialog",
                        info: "Check that '" + elementSelector + "' exists in the web page."

                    });
                    return;
                }

                jqElement.openClientSideDialog();


            } catch (e) {
                vpGrid.logException(e);
            }
        }




        vpGrid.openModalDialogWithSelectedItem = function (event, modalDialogId,position) {
            /// <signature>
            /// <summary>Event handler that opens the modal dialog window targeted by modalDialogId. 
            ///         Input controls on this dialog are filled with the data coming from the selected item in the grid.
            ///         The databinding is done through the data-tag attribute : data-vp-grid-column-name
            /// </summary>
            /// <param name="event" type="Object">Literal object passed by the click event</param>
            /// <param name="modalDialogId" type="String">value of the data attribute 'data-vp-grid-dialog-id'</param>
            /// </signature>
            try {
                if (isNullOrUndefinedOrEmpty(event)) {
                    //TODO : log
                    return;
                }

                if (isNullOrUndefinedOrEmpty(event.target)) {
                    vpGrid.logError({
                        message: "input parameter event is not a valid object : target property not found or not valid",
                        functionName: "vpGrid.openModalDialogWithSelectedItem",
                        info: "Check that vpGrid.openModalDialogWithSelectedItem is called by a click event on a DOM element."

                    });
                    return;
                }

                if (isNotString(modalDialogId)) {
                    vpGrid.logError({
                        message: "input parameter modalDialogId is not a valid string : '" + modalDialogId + "'",
                        functionName: "vpGrid.openModalDialogWithSelectedItem",
                        info: "Check that 'data-vp-grid-handlers' data attribute is correctly setup on the clicked button."
                    });
                    return;
                }

                var elementSelector = "div[role=vp-grid-modal-dialog][data-vp-grid-dialog-id=" + modalDialogId + "]";
                var jqElement = $(elementSelector);

                if (jqElement.notFound()) {
                    vpGrid.logError({
                        message: "Selector not found : '" + elementSelector + "'",
                        functionName: "vpGrid.openModalDialogWithSelectedItem",
                        info: "Check that '" + elementSelector + "' exists in the web page."

                    });
                    return;
                }

                jqElement.openClientSideDialogWithSelectedItem(position);


            } catch (e) {
                vpGrid.logException(e);
            }
        }




        vpGrid.bindDataSourceOnElement = function (element) {
            bindDataSourceOnElement(element);
        }
        // end vpGrid interface

        // vpGrid initialization
        vpGrid.init = function (options) {

            try {
                var jqContainer = vpGrid.currentContainer();

                if (jqContainer.notFound()) {
                    vpGrid.logError({
                        message: "vpGrid processing is stopped."
                    });
                    return;
                }

                //merge options
                if (isNotNullOrUndefinedOrEmpty(options)) {
                    $.extend(vpGridOptions, options);
                }

                //sanitize some options
                if (isNullOrUndefined(vpGridOptions.enableCustomCaption)) {
                    vpGridOptions.enableCustomCaption = true;
                }

                registerPrivateHandlers();

                Behaviors.executeTimeline();

                //prevent window closing if CRUD operations are not completed with server
                window.onbeforeunload = JQGrid.onBeforeUnload;

            } catch (e) {
                vpGrid.logException(e);
            }
        }

        //vpGrid ui notifier
        vpGrid.showUINotification = function (title, message,isPersistent) {
            try {
                if (isNullOrUndefinedOrEmpty(message)) {
                    return;
                }

                var containerSelector = 'div[id=vp-grid-ui-notification-area]';
                var jqContainer = $(containerSelector);

                if (jqContainer.notFound()) {
                    $('<div id="vp-grid-ui-notification-area" />').appendTo(document.body);
                    jqContainer = $(containerSelector);
                }

                var target = $('.qtip.jgrowl:visible:last');

                $('<div/>').qtip({
                    overwrite: true,
                    style: {
                        widget: true, // Use the jQuery UI widget classes
                        def: false, // Remove the default styling (usually a good idea, see below)
                        width: 250,
                        classes: 'jgrowl',
                        tip: false
                    },
                    content: {
                        text: message,
                        title: {
                            text: title,
                            button: true
                        }
                    },
                    position: {
                        target : [0,0],
                        container: jqContainer
                    },
                    show: {
                        event: false,
                        ready: true,
                        effect: function () {
                            $(this).stop(0, 1).animate({ height: 'toggle' }, 400, 'swing');
                        },
                        delay: 0,
                        persistent: isPersistent
                    },
                    hide: {
                        event: false,
                        effect: function (api) {
                            $(this).stop(0, 1).animate({ height: 'toggle' }, 400, 'swing');
                        }
                    },
                    events: {
                        render: function (event, api) {
                            if (!api.options.show.persistent) {
                                $(this).bind('mouseover mouseout', function (e) {
                                    var lifespan = 5000;

                                    clearTimeout(api.timer);
                                    if (e.type !== 'mouseover') {
                                        api.timer = setTimeout(function () { api.hide(e) }, lifespan);
                                    }
                                })
                                .triggerHandler('mouseout');
                            }
                        }
                    }

                });



            } catch (e) {
                vpGrid.logException(e);
            }
        }

        //end vpGrid initialization

    } catch (e) {
        vpGrid.logException(e);
    }
    finally {
        window.vpGrid = vpGrid;
    }
})(this, jQuery);

/* jqGrid extension for inserting inline summary rows inside jqGrid
    Each row may have a summary row placed after and/or before its current position
    Cell editing is automatically disabled for any summary row
*/
(function ($) {
    "use strict";
    $.jgrid = $.jgrid || {};
    $.jgrid.extend({
        addInlineSummaryRowData: function (rowid, rdata, pos, src) {
            //behaves like addRowData to insert a new summary row within the grid itself
            if (!pos) { pos = "last"; }
            var success = false, nm, row, gi, si, ni, sind, i, v, prp = "", aradd, cnm, cn, data, cm, id;
            if (rdata) {
                if ($.isArray(rdata)) {
                    aradd = true;
                    pos = "last";
                    cnm = rowid;
                } else {
                    rdata = [rdata];
                    aradd = false;
                }
                this.each(function () {
                    var t = this, datalen = rdata.length;
                    ni = t.p.rownumbers === true ? 1 : 0;
                    gi = t.p.multiselect === true ? 1 : 0;
                    si = t.p.subGrid === true ? 1 : 0;
                    if (!aradd) {
                        if (rowid !== undefined) { rowid = String(rowid); }
                        else {
                            rowid = $.jgrid.randId();
                            if (t.p.keyIndex !== false) {
                                cnm = t.p.colModel[t.p.keyIndex + gi + si + ni].name;
                                if (rdata[0][cnm] !== undefined) { rowid = rdata[0][cnm]; }
                            }
                        }
                    }
                    cn = t.p.altclass;
                    var k = 0, cna = "", lcdata = {},
                    air = $.isFunction(t.p.afterInsertRow) ? true : false;
                    while (k < datalen) {
                        data = rdata[k];
                        row = [];
                        if (aradd) {
                            try {
                                rowid = data[cnm];
                                if (rowid === undefined) {
                                    rowid = $.jgrid.randId();
                                }
                            }
                            catch (e) { rowid = $.jgrid.randId(); }
                            cna = t.p.altRows === true ? (t.rows.length - 1) % 2 === 0 ? cn : "" : "";
                        }
                        id = rowid;
                        rowid = t.p.idPrefix + rowid;
                        if (ni) {
                            prp = t.formatCol(0, 1, '', null, rowid, true);
                            row[row.length] = "<td role=\"gridcell\" class=\"ui-state-default jqgrid-rownum\" " + prp + ">0</td>";
                        }
                        if (gi) {
                            //v = "<input role=\"checkbox\" type=\"checkbox\"" + " id=\"jqg_" + t.p.id + "_" + rowid + "\" class=\"cbox\"/>";
                            v = "";
                            prp = t.formatCol(ni, 1, '', null, rowid, true);
                            //row[row.length] = "<td role=\"gridcell\" " + prp + ">" + v + "</td>";
                            row[row.length] = "<td role=\"summarygridcell\" " + prp + ">" + v + "</td>";
                        }
                        if (si) {
                            row[row.length] = $(t).jqGrid("addSubGridCell", gi + ni, 1);
                        }
                        for (i = gi + si + ni; i < t.p.colModel.length; i++) {
                            cm = t.p.colModel[i];
                            nm = cm.name;
                            lcdata[nm] = data[nm];
                            v = t.formatter(rowid, $.jgrid.getAccessor(data, nm), i, data);
                            //hdo
                            if (cm.isCheckbox) {
                                v = data[nm];
                            }
                            if (cm.isAction) {
                                v = '';
                            }
                            //
                            prp = t.formatCol(i, 1, v, data, rowid, lcdata);
                            row[row.length] = "<td role=\"summarygridcell\" " + prp + ">" + v + "</td>";
                        }
                        row.unshift(t.constructTr(rowid, false, cna, lcdata, data, false));
                        row[row.length] = "</tr>";
                        if (t.rows.length === 0) {
                            $("table:first", t.grid.bDiv).append(row.join(''));
                        } else {
                            switch (pos) {
                                case 'last':
                                    $(t.rows[t.rows.length - 1]).after(row.join(''));
                                    sind = t.rows.length - 1;
                                    break;
                                case 'first':
                                    $(t.rows[0]).after(row.join(''));
                                    sind = 1;
                                    break;
                                case 'after':
                                    sind = $(t).jqGrid('getGridRowById', src);
                                    if (sind) {
                                        if ($(t.rows[sind.rowIndex + 1]).hasClass("ui-subgrid")) { $(t.rows[sind.rowIndex + 1]).after(row); }
                                        else { $(sind).after(row.join('')); }
                                        sind = sind.rowIndex + 1;
                                    }
                                    break;
                                case 'before':
                                    sind = $(t).jqGrid('getGridRowById', src);
                                    if (sind) {
                                        $(sind).before(row.join(''));
                                        sind = sind.rowIndex - 1;
                                    }
                                    break;
                            }
                        }
                        if (t.p.subGrid === true) {
                            $(t).jqGrid("addSubGrid", gi + ni, sind);
                        }
                        //t.p.records++;
                        //t.p.reccount++;
                        //$(t).triggerHandler("jqGridAfterInsertRow", [rowid, data, data]);
                        //if (air) { t.p.afterInsertRow.call(t, rowid, data, data); }
                        k++;
                        if (t.p.datatype === 'local') {
                            //lcdata[t.p.localReader.id] = id;
                            //t.p._index[id] = t.p.data.length;
                            //t.p.data.push(lcdata);
                            lcdata = {};
                        }
                    }
                    if (t.p.altRows === true && !aradd) {
                        if (pos === "last") {
                            if ((t.rows.length - 1) % 2 === 1) { $(t.rows[t.rows.length - 1]).addClass(cn); }
                        } else {
                            $(t.rows).each(function (i) {
                                if (i % 2 === 1) { $(this).addClass(cn); }
                                else { $(this).removeClass(cn); }
                            });
                        }
                    }
                    //hdo
                    //t.updatepager(true, true);
                    success = true;

                    //add css class to further style the summary row
                    var jqRow = $("tr[role=row][id=" + rowid + "]");
                    jqRow.addClass("summary-row");

                    if (pos === 'after') {
                        jqRow.addClass("summary-row-after");
                    }

                    if (pos === 'before') {
                        jqRow.addClass("summary-row-before");
                    }

                    jqRow.find("td[role=summarygridcell]").addClass("summary-grid-cell");

                });
            }
            return success;
        },

        setInlineSummaryRowData: function (rowid, data, cssp) {
            var nm, success = true, title;
            this.each(function () {
                if (!this.grid) { return false; }
                var t = this, vl, ind, cp = typeof cssp, lcdata = {};
                ind = $(this).jqGrid('getGridRowById', rowid);
                if (!ind) { return false; }
                if (data) {
                    try {
                        $(this.p.colModel).each(function (i) {
                            nm = this.name;
                            var dval = $.jgrid.getAccessor(data, nm);
                            if (dval !== undefined) {
                                lcdata[nm] = this.formatter && typeof this.formatter === 'string' && this.formatter === 'date' ? $.unformat.date.call(t, dval, this) : dval;
                                vl = t.formatter(rowid, dval, i, data, 'edit');
                                if (this.isCheckbox) {
                                    vl = dval;
                                }
                                title = this.title ? { "title": $.jgrid.stripHtml(vl) } : {};
                                if (t.p.treeGrid === true && nm === t.p.ExpandColumn) {
                                    $("td[role='summarygridcell']:eq(" + i + ") > span:first", ind).html(vl).attr(title);
                                } else {
                                    $("td[role='summarygridcell']:eq(" + i + ")", ind).html(vl).attr(title);
                                    

                                }
                            }
                        });
                        if (t.p.datatype === 'local') {
                            var id = $.jgrid.stripPref(t.p.idPrefix, rowid),
                            pos = t.p._index[id], key;
                            if (t.p.treeGrid) {
                                for (key in t.p.treeReader) {
                                    if (t.p.treeReader.hasOwnProperty(key)) {
                                        delete lcdata[t.p.treeReader[key]];
                                    }
                                }
                            }
                            if (pos !== undefined) {
                                //hdo : do not change real data
                                //t.p.data[pos] = $.extend(true, t.p.data[pos], lcdata);
                            }
                            lcdata = null;
                        }
                    } catch (e) {
                        success = false;
                    }
                }
                if (success) {
                    //if (cp === 'string') { $(ind).addClass(cssp); } else if (cssp !== null && cp === 'object') { $(ind).css(cssp); }
                    //$(t).triggerHandler("jqGridAfterGridComplete");
                }
            });
            return success;
        },

        getCol: function (col, obj, mathopr) {
            //modified to skip inline summary cells
            var ret = [], val, sum = 0, min, max, v;
            obj = typeof obj !== 'boolean' ? false : obj;
            if (mathopr === undefined) { mathopr = false; }
            this.each(function () {
                var $t = this, pos = -1;
                if (!$t.grid) { return; }
                if (isNaN(col)) {
                    $($t.p.colModel).each(function (i) {
                        if (this.name === col) {
                            pos = i; return false;
                        }
                    });
                } else { pos = parseInt(col, 10); }
                if (pos >= 0) {
                    var ln = $t.rows.length, i = 0, dlen = 0;
                    if (ln && ln > 0) {
                        while (i < ln) {
                            if ($($t.rows[i]).hasClass('jqgrow') && !$($t.rows[i]).hasClass('summary-row')) {
                                try {
                                    val = $.unformat.call($t, $($t.rows[i].cells[pos]), { rowId: $t.rows[i].id, colModel: $t.p.colModel[pos] }, pos);
                                } catch (e) {
                                    val = $.jgrid.htmlDecode($t.rows[i].cells[pos].innerHTML);
                                }
                                if (mathopr) {
                                    v = parseFloat(val);
                                    if (!isNaN(v)) {
                                        sum += v;
                                        if (max === undefined) { max = min = v; }
                                        min = Math.min(min, v);
                                        max = Math.max(max, v);
                                        dlen++;
                                    }
                                }
                                else if (obj) { ret.push({ id: $t.rows[i].id, value: val }); }
                                else { ret.push(val); }
                            }
                            i++;
                        }
                        if (mathopr) {
                            switch (mathopr.toLowerCase()) {
                                case 'sum': ret = sum; break;
                                case 'avg': ret = sum / dlen; break;
                                case 'count': ret = (ln - 1); break;
                                case 'min': ret = min; break;
                                case 'max': ret = max; break;
                            }
                        }
                    }
                }
            });
            return ret;
        },

        getFilteredCol: function (col, obj, mathopr,isFiltered) {
            //modified to take only rows that are filtered by the callback function isFiltered()
            var ret = [], val, sum = 0, min, max, v;
            obj = typeof obj !== 'boolean' ? false : obj;
            if (mathopr === undefined) { mathopr = false; }
            this.each(function () {
                var $t = this, pos = -1;
                if (!$t.grid) { return; }
                if (isNaN(col)) {
                    $($t.p.colModel).each(function (i) {
                        if (this.name === col) {
                            pos = i; return false;
                        }
                    });
                } else { pos = parseInt(col, 10); }
                if (pos >= 0) {
                    var ln = $t.rows.length, i = 0, dlen = 0;
                    if (ln && ln > 0) {
                        while (i < ln) {
                            //hdo
                            //if ($($t.rows[i]).hasClass('jqgrow') && !$($t.rows[i]).hasClass('summary-row')) {
                            if (isFiltered($t.rows[i])) {
                                try {
                                    val = $.unformat.call($t, $($t.rows[i].cells[pos]), { rowId: $t.rows[i].id, colModel: $t.p.colModel[pos] }, pos);
                                } catch (e) {
                                    val = $.jgrid.htmlDecode($t.rows[i].cells[pos].innerHTML);
                                }
                                if (mathopr) {
                                    v = parseFloat(val);
                                    if (!isNaN(v)) {
                                        sum += v;
                                        if (max === undefined) { max = min = v; }
                                        min = Math.min(min, v);
                                        max = Math.max(max, v);
                                        dlen++;
                                    }
                                }
                                else if (obj) { ret.push({ id: $t.rows[i].id, value: val }); }
                                else { ret.push(val); }
                            }
                            i++;
                        }
                        if (mathopr) {
                            switch (mathopr.toLowerCase()) {
                                case 'sum': ret = sum; break;
                                case 'avg': ret = sum / dlen; break;
                                case 'count': ret = (ln - 1); break;
                                case 'min': ret = min; break;
                                case 'max': ret = max; break;
                            }
                        }
                    }
                }
            });
            return ret;
        },

        saveCell: function (iRow, iCol) {
            //modified to change call of the error modal dialog box
            return this.each(function () {
                var $t = this, fr;
                if (!$t.grid || $t.p.cellEdit !== true) { return; }
                if ($t.p.savedRow.length >= 1) { fr = 0; } else { fr = null; }
                if (fr !== null) {
                    var cc = $("td:eq(" + iCol + ")", $t.rows[iRow]), v, v2,
                    cm = $t.p.colModel[iCol], nm = cm.name, nmjq = $.jgrid.jqID(nm);
                    switch (cm.edittype) {
                        case "select":
                            if (!cm.editoptions.multiple) {
                                v = $("#" + iRow + "_" + nmjq + " option:selected", $t.rows[iRow]).val();
                                v2 = $("#" + iRow + "_" + nmjq + " option:selected", $t.rows[iRow]).text();
                            } else {
                                var sel = $("#" + iRow + "_" + nmjq, $t.rows[iRow]), selectedText = [];
                                v = $(sel).val();
                                if (v) { v.join(","); } else { v = ""; }
                                $("option:selected", sel).each(
                                    function (i, selected) {
                                        selectedText[i] = $(selected).text();
                                    }
                                );
                                v2 = selectedText.join(",");
                            }
                            if (cm.formatter) { v2 = v; }
                            break;
                        case "checkbox":
                            var cbv = ["Yes", "No"];
                            if (cm.editoptions) {
                                cbv = cm.editoptions.value.split(":");
                            }
                            v = $("#" + iRow + "_" + nmjq, $t.rows[iRow]).is(":checked") ? cbv[0] : cbv[1];
                            v2 = v;
                            break;
                        case "password":
                        case "text":
                        case "textarea":
                        case "button":
                            v = $("#" + iRow + "_" + nmjq, $t.rows[iRow]).val();
                            v2 = v;
                            break;
                        case 'custom':
                            try {
                                if (cm.editoptions && $.isFunction(cm.editoptions.custom_value)) {
                                    v = cm.editoptions.custom_value.call($t, $(".customelement", cc), 'get');
                                    if (v === undefined) { throw "e2"; } else { v2 = v; }
                                } else { throw "e1"; }
                            } catch (e) {
                                if (e === "e1") { $.jgrid.info_dialog($.jgrid.errors.errcap, "function 'custom_value' " + $.jgrid.edit.msg.nodefined, $.jgrid.edit.bClose); }
                                if (e === "e2") { $.jgrid.info_dialog($.jgrid.errors.errcap, "function 'custom_value' " + $.jgrid.edit.msg.novalue, $.jgrid.edit.bClose); }
                                else { $.jgrid.info_dialog($.jgrid.errors.errcap, e.message, $.jgrid.edit.bClose); }
                            }
                            break;
                    }
                    // The common approach is if nothing changed do not do anything
                    if (v2 !== $t.p.savedRow[fr].v) {
                        var vvv = $($t).triggerHandler("jqGridBeforeSaveCell", [$t.rows[iRow].id, nm, v, iRow, iCol]);
                        if (vvv) { v = vvv; v2 = vvv; }
                        if ($.isFunction($t.p.beforeSaveCell)) {
                            var vv = $t.p.beforeSaveCell.call($t, $t.rows[iRow].id, nm, v, iRow, iCol);
                            if (vv) { v = vv; v2 = vv; }
                        }
                        var cv = $.jgrid.checkValues.call($t, v, iCol);
                        if (cv[0] === true) {
                            var addpost = $($t).triggerHandler("jqGridBeforeSubmitCell", [$t.rows[iRow].id, nm, v, iRow, iCol]) || {};
                            if ($.isFunction($t.p.beforeSubmitCell)) {
                                addpost = $t.p.beforeSubmitCell.call($t, $t.rows[iRow].id, nm, v, iRow, iCol);
                                if (!addpost) { addpost = {}; }
                            }
                            if ($("input.hasDatepicker", cc).length > 0) { $("input.hasDatepicker", cc).datepicker('hide'); }
                            if ($t.p.cellsubmit === 'remote') {
                                if ($t.p.cellurl) {
                                    var postdata = {};
                                    if ($t.p.autoencode) { v = $.jgrid.htmlEncode(v); }
                                    postdata[nm] = v;
                                    var idname, oper, opers;
                                    opers = $t.p.prmNames;
                                    idname = opers.id;
                                    oper = opers.oper;
                                    postdata[idname] = $.jgrid.stripPref($t.p.idPrefix, $t.rows[iRow].id);
                                    postdata[oper] = opers.editoper;
                                    postdata = $.extend(addpost, postdata);
                                    $("#lui_" + $.jgrid.jqID($t.p.id)).show();
                                    $t.grid.hDiv.loading = true;
                                    $.ajax($.extend({
                                        url: $t.p.cellurl,
                                        data: $.isFunction($t.p.serializeCellData) ? $t.p.serializeCellData.call($t, postdata) : postdata,
                                        type: "POST",
                                        complete: function (result, stat) {
                                            $("#lui_" + $t.p.id).hide();
                                            $t.grid.hDiv.loading = false;
                                            if (stat === 'success') {
                                                var ret = $($t).triggerHandler("jqGridAfterSubmitCell", [$t, result, postdata.id, nm, v, iRow, iCol]) || [true, ''];
                                                if (ret[0] === true && $.isFunction($t.p.afterSubmitCell)) {
                                                    ret = $t.p.afterSubmitCell.call($t, result, postdata.id, nm, v, iRow, iCol);
                                                }
                                                if (ret[0] === true) {
                                                    $(cc).empty();
                                                    $($t).jqGrid("setCell", $t.rows[iRow].id, iCol, v2, false, false, true);
                                                    $(cc).addClass("dirty-cell");
                                                    $($t.rows[iRow]).addClass("edited");
                                                    $($t).triggerHandler("jqGridAfterSaveCell", [$t.rows[iRow].id, nm, v, iRow, iCol]);
                                                    if ($.isFunction($t.p.afterSaveCell)) {
                                                        $t.p.afterSaveCell.call($t, $t.rows[iRow].id, nm, v, iRow, iCol);
                                                    }
                                                    $t.p.savedRow.splice(0, 1);
                                                } else {
                                                    $.jgrid.info_dialog($.jgrid.errors.errcap, ret[1], $.jgrid.edit.bClose);
                                                    $($t).jqGrid("restoreCell", iRow, iCol);
                                                }
                                            }
                                        },
                                        error: function (res, stat, err) {
                                            $("#lui_" + $.jgrid.jqID($t.p.id)).hide();
                                            $t.grid.hDiv.loading = false;
                                            $($t).triggerHandler("jqGridErrorCell", [res, stat, err]);
                                            if ($.isFunction($t.p.errorCell)) {
                                                $t.p.errorCell.call($t, res, stat, err);
                                                $($t).jqGrid("restoreCell", iRow, iCol);
                                            } else {
                                                $.jgrid.info_dialog($.jgrid.errors.errcap, res.status + " : " + res.statusText + "<br/>" + stat, $.jgrid.edit.bClose);
                                                $($t).jqGrid("restoreCell", iRow, iCol);
                                            }
                                        }
                                    }, $.jgrid.ajaxOptions, $t.p.ajaxCellOptions || {}));
                                } else {
                                    try {
                                        $.jgrid.info_dialog($.jgrid.errors.errcap, $.jgrid.errors.nourl, $.jgrid.edit.bClose);
                                        $($t).jqGrid("restoreCell", iRow, iCol);
                                    } catch (e) { }
                                }
                            }
                            if ($t.p.cellsubmit === 'clientArray') {
                                $(cc).empty();
                                $($t).jqGrid("setCell", $t.rows[iRow].id, iCol, v2, false, false, true);
                                $(cc).addClass("dirty-cell");
                                $($t.rows[iRow]).addClass("edited");
                                $($t).triggerHandler("jqGridAfterSaveCell", [$t.rows[iRow].id, nm, v, iRow, iCol]);
                                if ($.isFunction($t.p.afterSaveCell)) {
                                    $t.p.afterSaveCell.call($t, $t.rows[iRow].id, nm, v, iRow, iCol);
                                }
                                $t.p.savedRow.splice(0, 1);
                            }
                        } else {
                            try {
                                //hdo
                                //window.setTimeout(function () { $.jgrid.info_dialog($.jgrid.errors.errcap, v + " " + cv[1], $.jgrid.edit.bClose); }, 100);
                                window.setTimeout(function () { $.jgrid.info_dialog($.jgrid.errors.errcap, cv[1], $.jgrid.edit.bClose); }, 100);

                                $($t).jqGrid("restoreCell", iRow, iCol);
                            } catch (e) { }
                        }
                    } else {
                        $($t).jqGrid("restoreCell", iRow, iCol);
                    }
                }
                window.setTimeout(function () { $("#" + $.jgrid.jqID($t.p.knv)).attr("tabindex", "-1").focus(); }, 0);
            });
        },

        footerData2: function (action, data, format,uiIdentifier) {
            var nm, success = false, res = {}, title;
            function isEmpty(obj) {
                var i;
                for (i in obj) {
                    if (obj.hasOwnProperty(i)) { return false; }
                }
                return true;
            }
            if (action == undefined) { action = "get"; }
            if (typeof format !== "boolean") { format = true; }
            action = action.toLowerCase();
            this.each(function () {
                var t = this, vl;
                if (!t.grid || !t.p.footerrow) { return false; }
                if (action === "set") { if (isEmpty(data)) { return false; } }
                success = true;
                $(this.p.colModel).each(function (i) {
                    nm = this.name;
                    if (action === "set") {
                        if (data[nm] !== undefined) {
                            vl = format ? t.formatter("", data[nm], i, data, 'edit') : data[nm];
                            title = this.title ? { "title": $.jgrid.stripHtml(vl) } : {};
                            $("tr[data-vp-grid-ui-id=" + uiIdentifier + "].footrow td:eq(" + i + ")", t.grid.sDiv).html(vl).attr(title);
                            success = true;
                        }
                    } else if (action === "get") {
                        res[nm] = $("tr[data-vp-grid-ui-id=" + uiIdentifier + "].footrow td:eq(" + i + ")", t.grid.sDiv).html();
                    }
                });
            });
            return action === "get" ? res : success;
        }

    });

    $.extend($.jgrid, {

        checkValues: function (val, valref, customobject, nam) {
            var edtrul, i, nm, dft, len, g = this, cm = g.p.colModel;
            if (customobject === undefined) {
                if (typeof valref === 'string') {
                    for (i = 0, len = cm.length; i < len; i++) {
                        if (cm[i].name === valref) {
                            edtrul = cm[i].editrules;
                            valref = i;
                            if (cm[i].formoptions != null) { nm = cm[i].formoptions.label; }
                            break;
                        }
                    }
                } else if (valref >= 0) {
                    edtrul = cm[valref].editrules;
                }
            } else {
                edtrul = customobject;
                nm = nam === undefined ? "_" : nam;
            }
            if (edtrul) {
                if (!nm) { nm = g.p.colNames != null ? g.p.colNames[valref] : cm[valref].label; }
                if (edtrul.required === true) {
                    if ($.jgrid.isEmpty(val)) { return [false, nm + ": " + $.jgrid.edit.msg.required, ""]; }
                }
                // force required
                var rqfield = edtrul.required === false ? false : true;
                if (edtrul.number === true) {
                    if (!(rqfield === false && $.jgrid.isEmpty(val))) {
                        if (isNaN(val)) { return [false, nm + ": " + $.jgrid.edit.msg.number, ""]; }
                    }
                }
                if (edtrul.minValue !== undefined && !isNaN(edtrul.minValue)) {
                    //if (parseFloat(val) < parseFloat(edtrul.minValue) ) { return [false,nm+": "+$.jgrid.edit.msg.minValue+" "+edtrul.minValue,""];}
                    if (parseFloat(val) < parseFloat(edtrul.minValue)) {
                        //hdo
                        var errorMessage = nm + ": " + $.jgrid.edit.msg.minValue + " " + edtrul.minValue ;
                        return [false, errorMessage, ""];
                    }


                }
                if (edtrul.maxValue !== undefined && !isNaN(edtrul.maxValue)) {
                    if (parseFloat(val) > parseFloat(edtrul.maxValue)) { return [false, nm + ": " + $.jgrid.edit.msg.maxValue + " " + edtrul.maxValue, ""]; }
                }
                var filter;
                if (edtrul.email === true) {
                    if (!(rqfield === false && $.jgrid.isEmpty(val))) {
                        // taken from $ Validate plugin
                        filter = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i;
                        if (!filter.test(val)) { return [false, nm + ": " + $.jgrid.edit.msg.email, ""]; }
                    }
                }
                if (edtrul.integer === true) {
                    if (!(rqfield === false && $.jgrid.isEmpty(val))) {
                        if (isNaN(val)) { return [false, nm + ": " + $.jgrid.edit.msg.integer, ""]; }
                        if ((val % 1 !== 0) || (val.indexOf('.') !== -1)) { return [false, nm + ": " + $.jgrid.edit.msg.integer, ""]; }
                    }
                }
                if (edtrul.date === true) {
                    if (!(rqfield === false && $.jgrid.isEmpty(val))) {
                        if (cm[valref].formatoptions && cm[valref].formatoptions.newformat) {
                            dft = cm[valref].formatoptions.newformat;
                            if ($.jgrid.formatter.date.masks.hasOwnProperty(dft)) {
                                dft = $.jgrid.formatter.date.masks[dft];
                            }
                        } else {
                            dft = cm[valref].datefmt || "Y-m-d";
                        }
                        if (!$.jgrid.checkDate(dft, val)) { return [false, nm + ": " + $.jgrid.edit.msg.date + " - " + dft, ""]; }
                    }
                }
                if (edtrul.time === true) {
                    if (!(rqfield === false && $.jgrid.isEmpty(val))) {
                        if (!$.jgrid.checkTime(val)) { return [false, nm + ": " + $.jgrid.edit.msg.date + " - hh:mm (am/pm)", ""]; }
                    }
                }
                if (edtrul.url === true) {
                    if (!(rqfield === false && $.jgrid.isEmpty(val))) {
                        filter = /^(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
                        if (!filter.test(val)) { return [false, nm + ": " + $.jgrid.edit.msg.url, ""]; }
                    }
                }
                if (edtrul.custom === true) {
                    if (!(rqfield === false && $.jgrid.isEmpty(val))) {
                        if ($.isFunction(edtrul.custom_func)) {
                            var ret = edtrul.custom_func.call(g, val, nm, valref);
                            return $.isArray(ret) ? ret : [false, $.jgrid.edit.msg.customarray, ""];
                        }
                        return [false, $.jgrid.edit.msg.customfcheck, ""];
                    }
                }
            }
            return [true, "", ""];
        }

    });
})(jQuery);
/* End jqGrid extensions */